[an error occurred while processing this directive] IT • archiv :: Print

IT • archiv


[an error occurred while processing this directive]

[an error occurred while processing this directive]

XML парсер на скорую руку

[an error occurred while processing this directive](none) [an error occurred while processing this directive](none)[an error occurred while processing this directive] ::
[an error occurred while processing this directive](none)
[an error occurred while processing this directive]([an error occurred while processing this directive] Стивен Р. Брандт [an error occurred while processing this directive])

[an error occurred while processing this directive](none)

Как анализировать XML, используя минимальный код.

Tips 'N Tricks
PDF versionPDF версия
Обзор
Этот совет показывает, как анализировать XML в апплете или другой среде с ограничением по объёму памяти, например, в приложении J2ME (Java 2 Platform, Micro Edition). Функциональные возможности ограничены настолько, насколько это допустимо для многих небольших приложений. (В оригинальной версии на английском языке 1000 слов)

XML — популярный формат данных по нескольким причинам: он человекочитаемый, самоописываемый и переносимый. К сожалению, многие XML-парсеры на базе Java являются очень большими; например, библиотеки jaxp.jar и parser.jar от Sun Microsystems — по 1,4 Мб каждая. Если объём памяти ограничен (например, в среде J2ME — Java 2 Platform, Micro Edition), или пропускная способность является критической (например, в апплете), использование таких больших парсеров может оказаться неприемлемым.

Частично причиной большого размера этих библиотек является большое количество функций, возможно, большее, чем необходимо. Они проверяют действительность XML DTD (определений типа документа), возможно, схем и т. д. Однако Вам может уже быть известно, что ваше приложение получит действительный XML. Также, Вы, возможно, уже решили, что хотите использовать только кодировку UTF-8. Поэтому Вам на самом деле необходима обработка XML-элементов на основе событий и преобразование стандартных XML-сущностей — т. е., Вам нужен парсер без проверки действительности.

Замечание
Исходный код для этой статьи можно загрузить по ссылке в «Ресурсах».

Почему бы просто не использовать SAX?

Вы могли бы реализовать интерфейсы SAX (Simple API for XML), ограничив функциональные возможности и выбрасывая исключение NotImplemented, столкнувшись с чем-нибудь ненужным.

Несомненно, можно было бы разработать что-то намного меньшее, чем библиотеки jaxp.jar / parser.jar по 1,4 Мб. Но вместо этого можно ещё больше сократить размер кода, определяя собственные классы. Фактически, пакет, который мы создаём здесь, будет значительно меньшим, чем JAR-файл, содержащий определения интерфейса SAX.

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

Ограничьте функциональность XML

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

Наш простой пакет для анализа имеет только один класс, QDParser, и один интерфейс, DocHandler. Сам QDParser имеет один публичный статический метод, parse(DocHandler,Reader), который мы реализуем как конечный модуль.

Наш парсер с ограниченными возможностямями обрабатывает DTD <! DOCTYPE> и инструкции по обработке <?xml version="1.0"?> просто как комментарии, так что на него не повлияют ни их присутствие, ни их содержание.

Поскольку мы не будем обрабатывать DOCTYPE, наш парсер не сможет читать пользовательские определения сущностей. Мы будем иметь дело только со стандартными: &amp, &lt;, &gt;, &apos; и &quot;. Если это проблема, можно вставить код, чтобы расширить пользовательские определения, как показано в исходном коде. В качестве альтернативы можно предварительно обработать документ, заменив пользовательские определения сущностей их развёрнутым текстом перед передачей документа в QDParser.

Наш парсер также не поддерживает разделы с условиями; например, <![INCLUDE[ ... ]]> или <![IGNORE[ ... ]]>. Без способности определять пользовательские определения сущностей в DOCTYPE эти функции в любом случае не нужны. Мы могли бы обработать такие разделы, если они имеются, до того как пересылать данные в наше приложение, ограниченное по памяти.

Поскольку мы не будем обрабатывать объявления атрибутов, спецификация XML требует, чтобы мы рассматривали все типы атрибутов как CDATA. Таким образом, мы можем просто использовать java.util.Hashtable вместо org.xml.sax.AttributeList, чтобы сохранять список атрибутов элемента. Мы имеем информацию только об имени/значении, чтобы использовать в Hashtable, но нам не нужен метод getType(), поскольку в любом случае он возвращал бы CDATA.

Отсутствие объявлений атрибутов имеет также другие последствия. Например, парсер не будет предоставлять значения атрибутов по умолчанию. Кроме того, мы не можем автоматически уменьшить незаполненное пространство, используя декларацию NMTOKENS. Однако мы могли сделать и то, и другое при подготовке нашего XML-документа, чтобы исключить дополнительное программирование из приложения, использующего парсер.

Фактически, все отсутствующие функциональные возможности можно компенсировать соответствующей предварительной подготовкой документа. Вы можете снять всю работу, связанную с отсутствующими особенностями (если они необходимы)1, с парсера на шаге подготовки документа.

Функциональные возможности парсера

Довольно о том, что парсер не может сделать. Что он может?

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

Как использовать этот пакет

Использовать XML-парсер на скорую руку просто. Прежде всего, реализуйте интерфейс DocHandler. Затем без проблем можно провести анализ файла с именем config.xml:

   DocHandler doc = new MyDocHandler();
   QDParser.parse(doc,new FileReader("config.xml"));

Исходный текст включает два примера, которые обеспечивают полную реализацию DocHandler. Первый DocHandler с именем Reporter просто выводит сообщения обо всех событиях в System.out по мере их прочтения. Вы можете проверить Reporter на файле-образце (config.xml).

Второй и более сложный пример, Conf, обновляет поля существующей структуры данных, которая постоянно находится в памяти. Conf использует пакет java.lang.reflect, чтобы найти местонахождение полей и объектов, описанных в config.xml. Если запустить эту программу, она будет печатать диагностическую информацию о том, какие объекты и как она обновляет. Она печатает сообщения об ошибках, если файл конфигурации требует, чтобы она обновила несуществующие поля.

Измените этот пакет

Вероятно, Вы захотите изменить этот пакет для своего приложения. Вы можете добавить пользовательские определения сущностей — строка 180 в QDParser.java содержит комментарий «Здесь вставляйте пользовательские определения сущностей».

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

Сохраняйте небольшой размер

Класс QDParser занимает приблизительно 3 Кб после компиляции и упаковки его в JAR-файл. Сам исходный текст с комментариями — чуть больше 300 строк. Это достаточно малый размер для большинства приложений с ограничением по объёму память и соблюдения спецификации XML в достаточной мере, чтобы воспользоваться большинством её полезных особенностей.

Об авторе

Стивен Брандт имеет докторскую степень в вычислительной астрофизике и является владельцем Stevesoft, компании, которая продаёт программное на Java на основе регулярных выражений.

Ресурсы

Reprinted with permission from the May 2002 edition of JavaWorld magazine. Copyright © ITworld.com, Inc., an IDG Communications company.
View the original article at: http://www.javaworld.com/javatips/jw-javatip128_p.html

[an error occurred while processing this directive]
[an error occurred while processing this directive] Перевод на русский © Дмитрий Габинский, 2003
< Вернуться на caйт :: Copyright © 1999 — 2010, IT • archiv.