Практически Groovy: Разметка с помощью Groovy Builders

Сконцентрируйтесь на приложении, а не на деталях языков разметки

Groovy Builders позволяют имитировать языки разметки, такие как XML и HTML, задачи Ant и даже графические оболочки на основе таких сред, как Swing. Они особенно полезны для быстрой разработки макетов и, как автор колонки Практически Groovy Эндрю Гловер (Andrew Glover) демонстрирует в этом выпуске, являются удобной альтернативой инфраструктурам связывания данных в случае, если необходимо очень быстро создать действующую разметку!

Эндрю Гловер, президент компании, Stelligent Incorporated

Эндрю ГловерЭндрю Гловер является президентом компании Stelligent Incorporated , которая помогает другим фирмам решать проблемы качества программного обеспечения. Для этого используются эффективные стратегии тестирования и технологии непрерывной интеграции, которые позволяют коллективам разработчиков постоянно контролировать качество кода, начиная с ранних стадий разработки. Просмотрите блог Энди , там можно найти список его публикаций.



12.10.2007

Несколько месяцев назад, когда я впервые написал про разработку сценариев Ant с помощью Groovy (En), я упомянул концепцию Builders в Groovy. В той статье я показал, как легко строить сложные build-файлы в Ant с помощью класса Groovy, который называется AntBuilder. В данной статье я углублюсь в мир Groovy Builders, чтобы продемонстрировать другие возможности этих мощных классов.

Использование Builders

Groovy Builders позволяют без особых усилий имитировать языки разметки, такие как XML, HTML, задачи Ant и даже графические оболочки на основе таких сред, как Swing. С помощью этого инструмента можно быстро создавать сложные типы разметок, такие как XML, при этом не имя дела с самим XML.

Принцип работы Builder довольно прост. Методы, прикрепленные к экземпляру Builder, соответствуют элементам некоторой разметки (как, например тег <body> в HTML). Объекты, созданные внутри замыканий, прикрепленных к методам, представляют собой узлы-потомки (например, тег <p> внутри оборачивающего его тега <body>).

Для наглядности я создам простой Builder, который программно представляет XML-документ, имеющий структуру, показанную в Листинге 1.

Об этой серии

Чтобы применять какой-либо инструмент в практике разработки, необходимо знать, как им пользоваться и когда его лучше отложить в сторону. Языки сценариев могут быть чрезвычайно полезным помощником, но только если применять их правильно и в подходящих ситуациях. В связи с этим в серии статей Практически Groovy мы рассматриваем практические применения Groovy и показываем, когда и как его можно успешно использовать.

Листинг 1. Простая XML-структура
 <person>
   <name first="Megan" last="Smith">
     <age>32</age>
     <gender>female</gender>
   </name>
   <friends>
     <friend>Julie</friend>
     <friend>Joe</friend>
     <friend>Hannah</friend>
   </friends>
 </person>

Создать представление такой структуры довольно легко. Сначала я прикрепляю метод person к экземпляру Builder, после чего последний начинает играть роль корневого узла XML <person>. Для создания узлов-потомков я создаю замыкание и объявляю новый объект name, который принимает параметры в виде map. Эти параметры, кстати, образуют основу атрибутов, прикрепленных к элементу.

Затем внутри объекта name я помещаю замыкание с двумя дополнительными объектами, age и gender, соответствующими аналогичным элементам-потомкам <name>. Вы уже поняли, в чем дело? Все очень просто.

Элементы <friends> и <person> имеют общего родителя, так что я выхожу из замыкания, объявляю объект friends и, конечно, прикрепляю замыкание, содержащее набор элементов friend, как показано в Листинге 2.

Листинг 2. Легкость использования Builders
import groovy.xml.*
import java.io.*

class XMLBuilder{

  static void main(args) {

    writer = new StringWriter()	 	
    builder = new MarkupBuilder(writer)
    friendnames = [ "Julie", "Joey", "Hannah"]

	builder.person() {
       name(first:"Megan", last:"Smith") {
         age("33")
         gender("female")
       }
       friends() {
         for (e in friendnames) { friend(e) }
       }
    }
    println writer.toString()
  }
}

Как видно, представление Groovy достаточно изящно и с легкостью сопоставляется с представлением соответствующей разметки. Внутри этого представления, очевидно, Groovy самостоятельно обрабатывает громоздкие элементы разметки (такие как < и >), позволяя сконцентрироваться на содержании, а не на особенностях структуры.


Как это работает с HTML

Builders могут также облегчить создание HTML, что может пригодиться при разработке Groovlets. В качестве простейшего примера представим, что мне нужно создать простую HTML-страницу, как в Листинге 3.

Листинг 3. HTML 101
 <html>
  <head>
   <title>Groov'n with Builders</title>
  </head>
  <body>
   <p>Welcome to Builders 101. As you can see this Groovlet is fairly simple.</p>
  </body>
 </html>

Я могу легко создать ее с помощью Groovy, как показано в Листинге 4.

Листинг 4. HTML 101 на Groovy
import groovy.xml.*
import java.io.* 

class HTMLBuilderExample{

  static void main(args) {
   writer = new StringWriter()	 	
   builder = new MarkupBuilder(writer)

   builder.html(){
     head(){
       title("Groov'n with Builders"){}
     }
     body(){
       p("Welcome to Builders 101. As you can see " +
         "this Groovlet is fairly simple.") 
     }
   }
   println writer.toString()
}

Давайте позабавимся еще и посмотрим, как просто создать полноценный графический интерфейс с помощью Builders. Ранее я упоминал, что класс Groovy SwingBuilder позволяет с легкостью создать графический интерфейс. В Листинге 5 показано, как работает SwingBuilder.

Листинг 5. GUI Builders на Groovy
import java.awt.FlowLayout
import javax.swing.*
import groovy.swing.SwingBuilder

class SwingExample{

  static void main(args) {
    swinger = new SwingBuilder()
    langs = ["Groovy", "Ruby", "Python", "Pnuts"]

	gui = swinger.frame(title:'Swinging with Groovy!', size:[290,100]) {
      panel(layout:new FlowLayout()) {
        panel(layout:new FlowLayout()) {
          for (lang in langs) {
            checkBox(text:lang)
          }
        }
        button(text:'Groovy Button', actionPerformed:{ 
swinger.optionPane(message:'Indubitably Groovy!').createDialog(null, 'Zen Message').show()
        })
        button(text:'Groovy Quit', actionPerformed:{ System.exit(0)})
     }
   }
   gui.show()
   }
}

А результат приведен на рис. 1. Неплохо, правда?

Рис. 1. Простой пример графического интерфейса на Groovy
Простой пример графического интерфейса на Groovy

Легко представить, насколько такой мощный инструмент как SwingBuilder может быть полезен для разработки прототипов.


Теперь посложнее

Эти примеры были очень простыми, хотя и забавными. Надеюсь, что я показал возможности Groovy Builders, позволяющие избегать базовых элементов разметки определенных языков, таких, как XML. Очевидно, что иногда предпочтительнее избегать XML или HTML , а средства, облегающие создание разметки для платформы Java™ , уже существуют. Например, одна из моих любимых сред, помогающих создавать XML – это JiBX.

С помощью JiBX можно легко связать структуру XML с объектной моделью, и наоборот. Связывание – это мощная парадигма, для реализации которой существует множество инструментов, таких как JAXB, Castor и Zeus.

Единственный недостаток подобных сред для связывания – они могут быть весьма сложны в работе. К счастью, Groovy Builders предоставляет более простое и зачастую не менее эффективное решение.


Псевдосвязывание с помощью Builders

Представьте на мгновение, что имеется простая база данных, представляющая словарь английских слов. Существует таблица для слов (words), их определений (definitions) и, наконец, таблица для синонимов (synonyms). На рис. 2 показано простое представление этой базы данных.

Рис. 2. База данных словаря
База данных словаря

Как видно, структура этой базы данных несложна: слова (words) связаны отношением типа один-ко-многим с определениями (definitions) и синонимами (synonyms).

В базе данных существует клиент, который потребляет структуру XML, отражающую основные принципы устройства содержимого этой базы данных. Искомая структура XML приведена в Листинге 6.

Листинг 6. XML, необходимый для словаря
<words>
  <word spelling="glib" partofspeech="adjective">
    <defintions>
      <defintion>Performed with a natural, offhand ease.</defintion>
      <defintion>Marked by ease and fluency of speech or writing that often suggests 
	  or stems from insincerity, superficiality, or deceitfulness</defintion>
    </defintions>
    <synonyms>
      <synonym spelling="artful"/> 
      <synonym spelling="urbane"/> 
    </synonyms>
  </word>	
</words>

Если вы решите реализовать это с помощью сред для связывания данных, таких как JiBX, то, вероятнее всего, придется создать некую промежуточную объектную модель, чтобы перейти от реляционной модели к необходимой модели XML. Затем придется переносить содержимое базы данных в эту промежуточную объектную модель, а потом использовать основную среду связывания данных для преобразования структуры промежуточной объектной модели в формат XML.

В этом процессе подразумевается также связывание среды с форматом XML (с помощью процедур выбранной среды). Некоторые среды, такие как JAXB,в действительности создают Java-объекты из XML и других сред, например JiBX, тем самым позволяя связать определенным образом ваши Java-объекты с форматом XML. В любом случае это может потребовать большого количества работы.

С другой стороны, труд – благородное дело. Я не выступаю против использования сред для связывания данных, а просто предупреждаю. А теперь я хочу показать более быстрый путь к созданию вышеупомянутого XML.

Быстрое создание XML, готовых к использованию

Используя Groovy MarkupBuilder вместе с новой уже знакомой вам инфраструктурой доступа к базам данных GroovySql, можно легко создавать готовые к использованию XML-файлы. Надо только понять, какие запросы вам потребуются, и связать результаты с экземпляром Builder. Вы сразу получите XML-документ, отражающий содержимое базы данных словаря.

Давайте шаг за шагом пройдем этот процесс. Сперва необходимо создать экземпляр Builder, в данном случае MarkupBuilder, потому что мы создаем XML. Самый наружным (корневым) элементом является words, поэтому нужно создать метод words. В замыкании сначала вызывается первый запрос, а его результаты связываются в итераторе с узлом-потомком word.

Затем необходимо создать два узла-потомка word с помощью двух новых запросов. Мы создаем объект definitions и связываем его в итераторе, а затем проделываем нечто подобное с synonyms.

Листинг 7. Собираем все вместе с помощью Builders
import groovy.sql.Sql
import groovy.xml.MarkupBuilder
import java.io.File
import java.io.StringWriter

class WordsDbReader{
  static void main(args) {
    sql = Sql.newInstance("jdbc:mysql://localhost/words", 
      "words", "words", "org.gjt.mm.mysql.Driver")
    writer = new StringWriter()	 	
    builder = new MarkupBuilder(writer)
    builder.words() {
      sql.eachRow("select word_id, spelling, part_of_speech from word"){ row |
        builder.word(spelling:row.spelling, partofspeech:row.part_of_speech){

		 builder.definitions(){
sql.eachRow("select definition from definition where word_id = ${row.word_id}"){ defrow |
              builder.definition(defrow.definition)
            }
         }

		 builder.synonyms(){  		       		
  sql.eachRow("select spelling from synonym where word_id = ${row.word_id}"){ synrow |
              builder.synonym(synrow.spelling)
            }		       					       		
         }
       }
      }
    }
   new File("dbouuput.xml").withPrintWriter{ pwriter |
      pwriter.println writer.toString()
   }
 }
}

Заключение

Приведенный пример связывания кажется предельно простым, особенно с точки зрения приверженцев «чистого» Java. Хотя это решение ничем не лучше того, которое можно было бы создать с помощью связывающей среды, такой как JABX или JiBX, оно безусловно быстрее, и я бы даже сказал, что легче. Мог бы я сделать что-нибудь подобное на обычном Java? Конечно, но при этом в какой-то момент мне бы пришлось иметь дело с XML.

Скорость и простота разработки с использованием Groovy Builders будут полезны в случаях, когда необходимо использовать разметку. Например, как было показано во втором примере, мне удалось очень быстро создать XML, представляющий базу данных. Builders также очень удобны, когда дело касается макетирования или когда необходимо разработать рабочее решение в сжатые сроки, используя при этом минимальное количество ресурсов.

О чем я расскажу в следующем месяце в Практически Groovy? Конечно же, об использовании Groovy в Java!

Ресурсы

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Технология Java, XML
ArticleID=261486
ArticleTitle=Практически Groovy: Разметка с помощью Groovy Builders
publish-date=10122007