Продолжается подписка на наши издания! Вы не забыли подписаться?

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

Автор: Бретт МакЛафлин
O'Reilly Media, Inc.
Опубликовано: 28.04.2009

Сериализация, TrAX или привязка к данным: что выбрать для сохранения 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"));

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

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. Есть и другие способы, не зависящие от конкретных библиотек, но они не столь наглядны для демонстрации.

Xerces – валидирующий XML-парсер, написанный на C++ в рамках проекта Apache.

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

Преимуществом сохранения через 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.

В частном случае можно использовать XSLT, не задающую никакого преобразования данных, и использовать ее для перевода документа из одного формата в другой. Использование такой таблицы стилей, которая просто дублирует входной документ, называется тождественным преобразованием. Таким образом, можно считать документ из файла, применить тождественное преобразование и получить тот же самый документ в виде 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.

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

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

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

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

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

Ниже представлен фрагмент кода в стиле 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.

От вас не требуется глубоких знаний 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 на сайте developerWorks (см. Ресурсы), а также сообщите нам, как вы решаете задачу сохранения XML. Если ваш выбор обусловлен необходимостью поддержки некой специальной функциональности, расскажите заодно и о ней. До встречи в online!

Ресурсы


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

Copyright © 1994-2016 ООО "К-Пресс"