XML и Java: Три подхода к сохранению XML (исходники)

Бретт МакЛафлин

XML-данные надо где-то хранить

XML - замечательный формат представления данных, что подтверждается и наличием целого раздела, посвященного XML, на сайте IBM developerWorks. В наши дни обсуждение XML зачастую проходит в контексте Web-сервисов, преобразований Java™-объектов в XML и обратно, и даже использования баз данных XML вместо реляционных или объектно-ориентированных.

В то же время мало кого интересует, каким образом XML-документы, представленные в памяти с помощью DOM, JDOM или чего-то еще, преобразуются в файлы на диске, полные угловых скобок и кавычек. Честно говоря, запись XML в файл - это не самое захватывающее занятие, но от него никуда не деться. Вы только попробуйте представить себе ситуацию, при которой невозможно сохранить XML-документ в файл! Вы можете создавать XML-документы в памяти и пересылать их между различными модулями вашего приложения (а может даже между несколькими приложениями), будучи не в состоянии сохранить где-либо данные. Например, можно создавать документы для представления конфигураций, разработав всевозможные полезные утилиты для их чтения, при этом не имея возможности их сохранить. Или же можно прочитать сообщение SOAP, но нельзя записать его в файл в случае потери сетевого соединения.

Таким образом, важность записи файлов XML совершенно очевидна. Более того, если бы никого не волновали вопросы длительного сохранения данных, а единственное, что было бы нужно - это всего лишь преобразовывать их в памяти, то вполне возможно, что в XML просто не было бы необходимости, и уж во всяком случае, он не был бы настолько важен, как в наши дни.

При этом остается простой вопрос: а как лучше сохранять XML-данные в файл? Эта статья в основном рассчитана на программистов, которым приходится этим заниматься. При этом если вы вообще не сталкивались с такой необходимостью, то статья также будет полезна, т.к. вы научитесь это делать. Для тех же из вас, кто занимается сохранением данных, я решил рассмотреть три основных подхода:

  1. Использование DOM, JDOM API и им подобных технологий для записи в файл напрямую из структур данных XML в памяти.
  2. Использование TrAX (Transformation API for XML) и тождественного преобразования для сохранения XML-данных.
  3. Использование высокоуровнего API, такого как JAXB.

Сохранение непосредственно через API

Если чтение XML-данных осуществляется с помощью одного или нескольких API, то вполне логично и сохранять XML-документ, используя те же API. К примеру, при работе с XML через JDOM API после получения ссылки на объект JDOM Document запись можно осуществлять следующим образом:

XMLOutputter outputter = new XMLOutputter();
outputter.setFormat(Format.getPrettyFormat());
outputter.output(myDocument, new FileWriter("outputFile.xml"));

Похожим образом можно записывать XML, используя новый API для загрузки и сохранения в спецификации DOM Level 3:

DOMWriter writer = new org.apache.xml.serialize.XMLSerializer();
writer.setNewLine("\r\n");
writer.setEncoding("UTF-8");
writer.writeNode(new FileOutputStream(new File("outputFile.xml")), myDocument);

Новый DOM API можно использовать множеством различных способов. При этом какие-то из них сильнее привязаны к конкретной реализации DOM API, например, как вышеприведенный класс, который использует Xerces. Хотя есть и другие способы, не зависящие от конкретных библиотек, они не столь наглядны для демонстрации.

Преимущества

Преимуществом сохранения через API является то, что вы работаете напрямую с API и, следовательно, держите все под контролем. Например, вы можете добавлять новые строки, указывать отступы и т.д., вплоть до мельчайших деталей. При этом мало, что отделяет вас от непосредственного доступа к файлу: нет ни оберток API, ни каких либо абстрактных слоев, так что вы можете работать с XML на очень низком уровне. Так что если вы уверенно владеете JDOM или DOM, то использование этих API - очень удобный способ сохранения XML-данных.

Недостатки

Недостатки прямого сохранения через API зачастую являются обратной стороной преимуществ. Из-за того, что практически все аспекты вывода находятся под контролем программиста, неправильное использование API легко может привести к неверному сохранению данных. Например, распространенными ошибками являются неправильные переводы строк, неверная кодировка, а также ошибки ввода-вывода. При этом приходится работать на очень низком уровне, практически без помощи каких либо вспомогательных утилит (JDOM предоставляет только методы Format.getPrettyFormat() и Format.getCompactFormat(), а DOM - и того меньше). Таким образом, необходимо досконально знать кодировки, форматы записи, правила отступов и остальные аспекты, имеющие какое либо значение для сохранения файла.

Форматы преобразования

Одна из популярных альтернатив - это использование TrAX и тождественного преобразования. TrAX - это API для XML-преобразований (Transformation API for XML). В настоящее время TrAX является частью JAXP, которая включаются практически во все релизы Java (кроме Micro Edition). TrAX позволяет использовать таблицы стилей XSL для преобразования XML-документов. TrAX предоставляет возможность преобразования SAX-событий или DOM-документов в XML-файлы и обратно, что удобно, т.к. SAX и DOM являются наиболее распространенными методами работы с XML. Например, можно взять DOM-документ, преобразовать его с помощью TrAX и сохранить результат в файле. Или же можно считать файл, преобразовать его и представить в виде DOM Document.

В частном случае можно использовать таблицу стилей, не задающую никакого преобразования данных, и использовать ее для перевода документа из одного формата в другой. Использование такой таблицы стилей, которая просто дублирует входной документ, называется тождественным преобразованием. Таким образом, можно считать документ из файла, применить тождественное преобразование и получить тот же самый документ в виде DOM. Обратное действие-из DOM в файл-является ничем иным, как сохранением XML. Это делается примерно так:

Source domSource = new DOMSource(myDOMDocument);
Result fileResult = new StreamResult(new File("outputFile.xml"));
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
transformer.transform(domSource, fileResult);

В этом примере DOM-документ сохраняется в XML-файле outputFile.xml.

Преимущества TrAX

Наибольшим плюсом TrAX является простота использования. TrAX легко вызывается из Java-кода и не требует серьезных знаний SAX или DOM, что делает его очень привлекательным для программистов, не обладающих уверенными навыками работы с XML. Вдобавок, его могут использовать начинающие программисты, незнакомые с SAX или DOM, т.к. достаточно выучить 10-20 строк кода и можно сохранять XML-данные в файл или преобразовывать в DOM-документы и наборы SAX-событий.

Обратная сторона использования TrAX

Наибольшим недостатком TrAX является то, что при всей простоте преобразований, достаточно трудно контролировать мелкие детали вывода, такие как переводы строк, кодировки, пробелы и отступы. TrAX поддерживает работу с этими аспектами сохранения, но это далеко не так просто, как в случае непосредственного использования DOM или JDOM. Как правило, простота использования TrAX сочетается с недостатком гибкости при сохранении в файл, по крайней мере, на первый взгляд.

При этом, практически всего, что можно делать через DOM или JDOM, можно достичь и при использовании TrAX, но это не настолько просто и интуитивно. Приходится вникать в детали XSLT и TrAX API, которые имеют весьма слабое отношение к практическим задачам сохранения XML.

Использования привязки к данным (data binding) для сохранения XML

Еще одним способом перевода XML в статическое представление-особенно, если это представление должно быть в виде файла на диске-является использование API для привязки к данным (data binding), таких как JAXB. Несмотря на то, что привязка к данным, как правило, не рассматривается в качестве метода их сохранения, она фактически является таковым. Это не что иное, как способ взять XML-документ в памяти и записать его в файл.

К сожалению, ввиду ограниченности объема статьи, я не могу подробно рассказать, что такое привязка к данным, но вы можете прочитать несколько статей на эту тему на сайте developerWorks. Ниже представлен фрагмент кода в стиле JAXB, который сохраняет XML на диск:

FileOutputStream stream = new FileOutputStream("outputFile.xml");
Marshaller marshaller = myJaxbContext.createMarshaller();
marshaller.marshal(myJavaObject, stream);

Вы можете задавать различные параметры, такие как кодировка выходного файла через объект Marshaller. В смысле гибкости настройки параметров вывода, JAXB не сильно отличается от вышерассмотренных подходов.

Преимущества JAXB

Одним из наиболее существенных преимуществ JAXB является простота использования, особенно при решении несложных задач. К тому же, в то время как SAX и DOM считаются достаточно сложными в использовании (по крайней мере, в кругу рядовых программистов), понимание JAXB необходимо практически каждому Java-разработчику. Как следствие, выложено много статей и руководств по JAXB, что подтверждается обзорами публикаций на сайтах типа developerWork за 2007 год. Кроме этого, JAXB лучше поддерживается, чем DOM или SAX. Несмотря на то, что реализации SAX и DOM также включены в релизы Java-платформы, JAXB является детищем Sun Microsystems, так что его поддержка обещает быть лучше.

От вас не требуется глубоких знаний XML, чтобы начать использовать JAXB. Вы можете работать с обыкновенными Java-объектами (а не специфическими интерфейсами, типа Node или Text в DOM), а затем сохранить их в XML. Как следствие, вам не придется изучать гору нового материала, перед тем как начать работать с JAXB, что особенно ценно, когда ваш босс требует от вас результатов немедленно.

Недостатки JAXB

В то же время необязательность знания XML также является определенным недостатком JAXB, потому как чем меньше вы знаете об XML, тем сложнее разумно использовать JAXB. В итоге, может запросто получиться плохо отформатированный XML-документ или документ, в котором присутствует только часть объектов, а, может, и вовсе не те объекты, которые должны были быть сохранены.

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

И последний подход...

Я сознательно обошел вниманием еще один вариант формирования XML-файла, а именно: запись последовательности бит, байт и строк непосредственно в FileOutputStream или FileWriter. Это вполне осуществимо на практике и иногда используется. Однако в этом случае вместо сохранения XML-данных происходит просто создание нового XML-документа на основе данных, представленных в каком-либо другом формате. Подобные действия легко распознать на практике, потому как код, как правило, выглядит как на фрагменте ниже:

String xmlString = setupXMLBuffer(
  new StringBuffer("<firstName>")
       .append(customer.firstName)
       .append("</firstName>")
       .append("<lastName>")
       .append(customer.lastName)
       .append("</lastName>")
  // etc...
       .toString()
);
bufferedWriter.write(xmlString);
// other file I/O code

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

Заключение

В целом не существует единственно верного подхода к сохранению XML-документов, так что полезно обсуждать различные варианты, используемые разными Java и XML-разработчиками. Главное, спросите себя, является ли ваш подход к этой общей проблеме последовательным? Позволяет ли он сохранять XML-документы на диске в виде, удобном для последующего использования: чтения, понимания и обмена данными между приложениями?

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


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