Упрощение XML-программирования при помощи JDOM

JDOM является уникальным Java-инструментом для работы с XML, он создан для обеспечения быстрой разработки XML-приложений. В его проекте использованы синтаксис и семантика языка Java. Но лучше ли он, чем существующие - и более стандартизированные - API для XML? Судите об этом сами по мере того, как мы будем проходить через ряд примеров и освещать цели этого популярного проекта с открытым кодом, который сейчас официально принят как Java Specification Request.

Как разработчик, вы, возможно, слышали о правиле 80-20, известном в других кругах как закон Парето: процесс или методология будет приспособлен для 80 процентов всех возможных ситуаций, а остальные 20 придется обрабатывать по-разному, от случая к случаю. Вывод для разработки программного обеспечения - что разработчикам должно быть очень легко выполнить 80 процентов из того, что им нужно сделать при помощи данной технологии. Конечно, программные продукты и стандарты не всегда развиваются в соответствии с правилом 80-20. Раздробленная сфера инструментов Java XML, в частности, иллюстрирует исключение из этого правила. Мир программирования Java полон разных APIs - некоторые из них доморощенные, некоторые пришли на рынок от ведущих корпораций - которые обеспечивают изощренные решения для определенных задач XML. Как бы в соответствии с универсальностью XML, для каждой новой задачи есть новая технология. Но как их склеить, и как вы собираетесь найти правильный инструмент для 80 процентов вещей, которые вы должны делать снова и снова - на основе манипулирования деревом XML с интуитивным отображением на язык Java? JDOM - это XML API, построенные именно для решения этого вопроса.

Итак, мы здесь: Java и XML

Во многих отношениях язык Java стал языком программирования для XML. Благодаря значительной работе Apache Software Foundation и IBM alphaWorks, сейчас есть полная цепочка инструментов для создания, манипулирования, преобразования и разбора XML-документов. Но хотя множество Java-разработчиков используют XML ежедневно, Sun задерживает индустриальное внедрение XML в платформу Java. Поскольку платформа Java 2 прекрасно развивалась до того, как XML обозначил себя как ключевая технология для всего, от интеграции бизнеса с бизнесом и до наполнения Web-сайтов, фирма Sun использовала процесс JSR в качестве дедушки существующих XML API, которые получили широкое применение. Наиболее значительным на сегодня добавлением было введение JAXP, Java API for XML Parsing, который включает в себя три пакета:

  • org.w3c.dom, Java-реализация рекомендации W3C для стандартной программной Объектной Модели Документа для XML
  • org.xml.sax, Simple API for XML для разбора, управляемого событиями
  • javax.xml.parsers, фабричная реализация, которая позволяет разработчикам приложений конфигурировать и получать определенную реализацию парсера

Хотя введение этих пакетов является хорошей вещью для Java-разработчиков, они только представляют формальный поклон существующим стандартам API, а не большой скачок вперед в обеспечении элегантной интероперабельности Java-XML. Чего недостает в базовой платформе Java, так это интуитивного интерфейса для манипулирования XML-документами как Java-объектами.

Появляется JDOM. Дитя двух известных Java-разработчиков и авторов, Брэта Маклафлина и Джейсона Хантэра, JDOM был введен в действие как проект с открытым кодом по лицензии, подобной Apache, в начале 2000 года. Он рос, включая в себя вклады, и учитывая обратную связь и исправления ошибок от широкого круга Java-разработчиков и стремясь построить полное решение на платформе Java для обращения, манипулирования и вывода XML-данных из кода Java.

Для чего годится JDOM

JDOM может использоваться как альтернатива пакету org.w3c.dom для программного манипулирования XML-документами. Это не обязательная замена, фактически JDOM и DOM могут счастливо сосуществовать. Кроме того, JDOM не занимается разбором исходного текста XML, хотя он обеспечивает классы-оболочки, которые берут на себя большую часть работы по конфигурированию и выполнению реализации парсера. JDOM использует сильные стороны существующих API, чтобы построить, как сказано на домашней странице проекта, "лучшую мышеловку".

Чтобы понять, зачем нужен альтернативный API, рассмотрим ограничения проекта W3C DOM:

  • Независимость от языка. DOM не была разработана, имея в виду язык Java. Хотя этот подход сохраняет очень похожий API для разных языков, он также делает этот API более громоздким для программистов, которые используют стиль языка Java. Например, хотя язык Java имеет встроенный в язык класс String, спецификация DOM определяет собственный класс Text.
  • Строгая иерархия. API DOM следует непосредственно самой спецификации XML. В XML все является узлами, так что вы находите в DOM интерфейс на базе узлов, где почти все строится на методах, которые возвращают Node. Это элегантно с точки зрения полиморфизма, но, как объяснялось выше, трудно и громоздко работать с этим в языке Java, где явное схождение от Node к типам листьев приводит к громоздкому и плохо понимаемому коду.
  • Управляемый интерфейсом. DOM API состоит только из интерфейсов (единственным, вполне достаточным исключением является класс Exception). В сферу интересов W3C не входит обеспечение реализаций, только определение интерфейсов, что имеет смысл. Но это также означает, что использующий API Java-программист при создании объектов XML в некоторой степени ущемлен, так как стандарты W3C затрудняют использование классов родовых фабрик и подобных гибких, но менее непосредственных шаблонов. Для определенных вариантов использования, когда XML-документы строятся только парсером и никогда - прикладным кодом, это не имеет значения. Но когда использование XML становится более широким, не все проблемы продолжают оставаться управляемыми только парсером, и разработчики приложений нуждаются в удобном способе конструировать объекты XML программно.

Для программистов эти ограничения означают тяжелый (и в смысле использования памяти, и в смысле размера интерфейса) и громоздкий API, который может быть трудно изучить и использовать. Напротив, JDOM сформулирован как легкий API, прежде всего ориентированный на Java. Он отвечает перечисленным выше требования, следуя основным принципам DOM, но имеет свои особенности:

  • JDOM специализирован для платформы Java. API использует, где возможно, встроенную в Java поддержку String, так что текстовые значения всегда доступны как String. Он также использует классы коллекций платформы Java 2, такие как List и Iterator, обеспечивая богатую среду для работы программистов, хорошо знакомых с языком Java.
  • Нет иерархий. В JDOM элемент XML является экземпляром класса Element, атрибут XML является экземпляром класса Attribute, а сам XML-документ является экземпляром класса Document. Поскольку все они представляют разные концепции в XML, они всегда представляются собственными типами, а не как аморфные "узлы".
  • Управляемый классом. Поскольку объекты JDOM являются непосредственными экземплярами таких классов, как Document, Element и Attribute, создание их настолько легко, насколько легко использование оператора new языка Java. Это также означает, что нет необходимости в интерфейсе фабрики для конфигурирования - JDOM готов к использованию прямо из jar.

Построение документов JDOM и манипулирование ими

JDOM использует стандартные шаблоны кодирования Java. Где возможно, он использует оператор Java new вместо сложных шаблонов фабрик, делая манипулирование объектами легким даже для начинающего. Например, давайте посмотрим, как вы можете построить простой XML-документ с нуля, используя JDOM. Структура, которую мы собираемся построить, показана в Листинге 1.

Листинг 1. Простой XML-документ для построения

<?xml version="1.0" encoding="UTF-8"?>
<car vin="123fhg5869705iop90">
  <!--Description of a car-->
  <make>Toyota</make>
  <model>Celica</model>
  <year>1997</year>
  <color>green</color>
  <license state="CA">1ABC234</license>
</car>

Замечание: Мы будем строить документ-пример, подробнее в Листингах 2 - 7 далее.

Для начала давайте создадим корневой элемент и добавим его в документ:

Листинг 2. Создание документа

Element carElement = new Element("car");
Document myDocument = new Document(carElement);

Этот шаг создает новый элемент org.jdom.Element и делает его корневым элементом org.jdom.Document myDocument. (Если вы используете код примера, из Ресурсов, убедитесь, что импортирован org.jdom.* .) Поскольку XML-документ должен всегда иметь единственный корневой элемент, Document принимает в своем конструкторе Element.

Далее мы добавляем атрибут vin:

Листинг 3. Добавление атрибута

carElement.addAttribute(new Attribute("vin", "123fhg5869705iop90"));

Добавление элементов также весьма очевидно. Вот мы добавляем элемент make:

Листинг 4. Элементы и подэлементы

Element make = new Element("make");
make.addContent("Toyota");
carElement.addContent(make);

Поскольку метод addContent класса Element возвращает Element, мы можем также написать это так:

Листинг 5. Добавление элемента в краткой форме

carElement.addContent(new Element("make").addContent("Toyota"));

Оба эти оператора выполняют одно и то же. Некоторые могут сказать, что первый пример более читабельный, но другим покажется более читабельным конструирование многих элементов за раз. Чтобы завершить конструирование документа:

Листинг 6. Добавление остальных элементов

carElement.addContent(new Element("model").addContent("Celica"));
carElement.addContent(new Element("year").addContent("1997"));
carElement.addContent(new Element("color").addContent("green"));
carElement.addContent(new Element("license")
    .addContent("1ABC234").addAttribute("state", "CA"));

Вы заметите, чтоб для элемента license мы не только добавляем содержимое элемента, но также и добавляем к нему атрибут, определяющий штат, в котором лицензия выдана. Это возможно потому, что методы addContent класса Element всегда возвращают сам Element, а не имеют декларацию void.

Добавление комментария или других стандартных типов XML проделывается тем же способом:

Листинг 7. Добавление комментария

carElement.addContent(new Comment("Description of a car"));

Манипулирование документов выполняется в том же стиле. Например, чтобы получить ссылку на элемент year, мы используем метод getChild класса Element:

Листинг 8. Обращение к дочерним элементам

Element yearElement = carElement.getChild("year");

Этот оператор будет возвращать первый дочерний Element с именем элемента year. Если элемента year нет, вызов вернет null. Заметьте, что нам не нужно преобразовывать возвращаемое значение во что-то вроде интерфейса DOM Node - потомки Element'ов - просто Element'ы. Таким же образом мы можем удалить из документа элемент year:

Листинг 9. Удаление дочерних элементов

boolean removed = carElement.removeChild("year");

Этот вызов удалит только элемент year; остальная часть документа останется неизмененной.

Итак, мы рассмотрели, как документы могут создаваться и как ими манипулировать. Для вывода нашего окончательного документа на консоль мы можем использовать класс JDOM XMLOutputter:

Листинг 10. Настройка JDOM на текст XML

try {
    XMLOutputter outputter = new XMLOutputter("  ", true);
    outputter.output(myDocument, System.out);
} catch (java.io.IOException e) {
    e.printStackTrace();
}

XMLOutputter имеет несколько опций форматирования. Здесь мы задали, что мы хотим, чтобы дочерние элементы отступали на два пробела от родительских элементов, и что мы хотим иметь переводы строки между элементами. XMLOutputter может выводить либо во Writer, либо в OutputStream. Чтобы выводить в файл, мы можем просто изменить строку вывода на:

Листинг 11. Использование FileWriter для вывода XML

FileWriter writer = new FileWriter("/some/directory/myFile.xml");
outputter.output(myDocument, writer);
writer.close();

Хорошо играет с другими: Взаимодействие с существующими инструментами XML

Одним из интересных свойств JDOM является его интероперабельность с другими API. Используя JDOM, вы можете выводить документ не только в Stream или в Reader, но также и в поток событий SAX или в DOM Document. Эта гибкость позволяет JDOM использоваться в гетерогенной среде или добавляться в систему, уже применяющую другие методы для обработки XML. Как мы увидим в следующем примере, она также позволяет JDOM использовать другие инструменты XML, которые даже не распознают структуры данных JDOM.

Другое использование JDOM состоит в возможности читать и манипулировать уже существующими XML-данными. Чтение правильно форматированного XML-файла выполняется при помощи одного из классов в org.jdom.input. В данном примере мы применяем SAXBuilder:

Листинг 12. Разбор XML-файла при помощи SAXBuilder

try {
  SAXBuilder builder = new SAXBuilder();
  Document anotherDocument = 
    builder.build(new File("/some/directory/sample.xml"));
} catch(JDOMException e) {
  e.printStackTrace();
} catch(NullPointerException e) {
  e.printStackTrace();
}

Вы можете манипулировать документом, построенным таким способом, так же, как было показано выше, в Листингах 2 - 7.

Другое практическое приложение JDOM комбинирует его с продуктом Xalan от Apache (см Ресурсы). Используя вышеприведенный пример с автомобилем, мы сконструируем Web-страницу для онлайнового продавца автомобилей, представляющую подробности об определенном автомобиле. Сначала предположим, что документ, построенный нами выше, представляет информацию об автомобиле, которую мы хотим представить пользователю. Далее мы скомбинируем этот Document JDOM с таблицей стилей XSL и выведем отформатированные в HTML результаты в OutputStream сервлета для отображения в браузере пользователя.

В данном случае таблица стилей XSL, которую мы собираемся использовать, называется car.xsl:

Листинг 13. XSL для трансформации записи об автомобиле в HTML

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/car">
    <html>
        <head>
          <title><xsl:value-of select="make"/> <xsl:value-of select="model"/>
        </head>
        <body>
          <h1><xsl:value-of select="make"/></h1><br />
          <h2><xsl:value-of select="model"/></h2><br />
          <table border="0">
          <tr><td>VIN:</td><td><xsl:value-of select="@vin"/></td></tr>
          <tr><td>Year:</td><td><xsl:value-of select="year"/></td></tr>
          <tr><td>Color:</td><td><xsl:value-of select="color"/></td></tr>
          </table>
        </body>
    </html>
  </xsl:template>
</xsl:stylesheet>

Теперь мы настроим org.jdom.Document на Document DOM и скормим его Xalan, вместе с файлом, который представляет наш XSL, и OutputStream, который мы получили от нашего гипотетического сервера приложений, который используется сервлетом (Листинг 14).

Листинг 14. Создание HTML-документа при помощи JDOM и Xalan

TransformerFactory tFactory = TransformerFactory.newInstance();

// Make the input sources for the XML and XSLT documents
org.jdom.output.DOMOutputter outputter = new org.jdom.output.DOMOutputter();
org.w3c.dom.Document domDocument = outputter.output(myDocument);
javax.xml.transform.Source xmlSource = 
  new javax.xml.transform.dom.DOMSource(domDocument);
StreamSource xsltSource = 
  new StreamSource(new FileInputStream("/some/directory/car.xsl"));

// Make the output result for the finished document using 
// the HTTPResponse OutputStream
StreamResult xmlResult = new StreamResult(response.getOutputStream());

// Get a XSLT transformer
Transformer transformer = tFactory.newTransformer(xsltSource);

// Do the transform
transformer.transform(xmlSource, xmlResult);

В данном примере вывод происходит через HTTPResponse OutputStream Java-сервлета. Однако, поток может так же легко быть и файловым потоком, как в предыдущем примере с XMLOutputter. Мы использовали DOMOutputter при генерации источника XML для Xalan. Однако, мы могли генерировать тот же вход, используя XMLOutputter для вывода XML-документа как String, а затем превратить его в StreamSource. Отметим гибкость: JDOM может выводить свои структуры как String, как поток событий SAX или как Document DOM. Это позволяет JDOM иметь интерфейс с инструментами, которые могут принимать на входе любую из этих моделей. (Если вам нужна дополнительная функциональность, проверьте пакет contrib на Web-сайте JDOM, где вы найдете большую библиотеку утилит JDOM, которые обеспечивают такие инструменты, как построитель JDBC на основе ResultSet, реализацию XPATH и т.п.)

Всего в нескольких строках кода JDOM обеспечивает большое разнообразие функциональности. Мы можем разбирать и программно создавать XML-документы, манипулировать этими документами и использовать их для выработки Web-страниц, управляемых XML.

JDOM растет: Взгляд в будущее

Когда это пишется, проект JDOM реализован в версии Beta 6. Даже в бета-состоянии JDOM обеспечивает стабильную реализацию для многих реальных приложений. Хотя многие из API уже надежны, продолжается работа во многих областях, которая потенциально повлияет на существующие интерфейсы. Следовательно, никакие проекты-разработки, предпринятые в настоящее время, не должны избегать JDOM из боязни ошибочной реализации, но должны рассматривать возможность того, что определенные сигнатуры методов или специфическая семантика все еще могут измениться до финального релиза и потенциальной адаптации в ядро Java API.

На ближайшее время список того, что нужно сделать для JDOM фокусируется на стабилизации API и оценке аспектов производительности частей реализации. Другие пункты находятся в работе, но это может помешать некоторым разработчикам приложений включать поддержку сущностей DTD и других более редких конструкций. Дорога дальше предусматривает включение в ядро поддержку XPATH, языка маршрутов XML непосредственно в приложения, как XSLT, и более прямую интеграцию с источниками данных XML.

Итак, в заключение, лучше ли JDOM, чем существующие API XML? Если вы думаете на Java, ответ, возможно, да. JDOM не означает отставки вашему любимому парсеру или XML-базе данных, но его принципы проектирования направлены на ускорение обучения Java-разработчиков или их ориентирование в мире XML.


Страница сайта http://test.interface.ru
Оригинал находится по адресу http://test.interface.ru/home.asp?artId=3078