КаталогИндекс раздела


©IBM developerWorks
© А.С.Деревянко (перевод)

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

Этот API с открытым кодом облегчает манипулирование XML-документом для разработчиков Java

Wes Biggs, Senior Developer, T.H.I.
Harry Evans, Senior Developer, T.H.I.

01 мая 2001 г.

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, который включает в себя три пакета:

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

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

Это API, дурак: Для чего годится JDOM

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

Для программистов эти ограничения означают тяжелый (и в смысле использования памяти, и в смысле размера интерфейса) и громоздкий API, который может быть трудно изучить и использовать. Напротив, JDOM сформулирован как легкий API, прежде всего ориентированный на Java. It does away with the above awkwardness by turning the DOM's principles on their head:

Смотри, ма, нет узлов: Построение документов 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();

// Создание источника для документов XML и XSLT 
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"));

// Создание вывода результатов для конечного документа 
// при помощи HTTPResponse OutputStream
StreamResult xmlResult = new StreamResult(response.getOutputStream());

// Получение преобразователя XSLT 
Transformer transformer = tFactory.newTransformer(xsltSource);

// Выполнение преобразования
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.

Sun и JDOM: Что в имени?

Официальный релиз JDOM, 1.0, может совместиться с его продолжающимся оцениванием в Java Community Process. Представленный в JCP как JSR-102, JDOM был одобрен для возможного включения в ядро платформы Java с таким комментарием от Sun: "JDOM выглядит значительно более легким в использовании, чем прежние API, так что мы надеемся, что он будет полезным дополнением к платформе." В соответствии с JSR, в релизе 1.пакеты JDOM могут измениться с "org.jdom" на "javax.xml.tree".

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

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

Ресурсы

Об авторах

Wes Biggs разрабатывал Internet-приложения для таких компаний, как Los Angeles Times, USWeb и Elite Information Systems. Он часто делал вклады в Java-проекты с открытым кодом и поддерживает пакет регулярных выражений gnu.regexp Free Software Foundation. Его адрес: wes@tralfamadore.com.

Опыт Harry Evans в разработке программного обеспечения и приложений включает в себя разработку нескольких Web-базированных Internet-продуктов, в основном в инновационных средах. Он работал на всех стадиях жизненного цикла продуктов, от Rapid Application Development до интеграции унаследованных продуктов. Его адрес: harry@tralfamadore.com.


КаталогИндекс раздела