PHP-4 Эффективная работа


Что такое XML и как с ним работать?
XML и Expat
Функции XML-анализатора
Практический подход к анализу XML-документов

Язык XML за последние пару лет приобрел достаточно широкую популярность у разработчиков информационных систем. Хотя, с моей точки зрения, на сегодняшний день его практическая область применения относится больше к использованию в качестве переговорного множества между различными СУБД, постепенно появляются различные приложения и библиотеки, которые позволяют использовать его и в «полезных целях».

XML представляет собой стандарт консорциума W3C, предназначенный для создания представления документов, обладающего следующими характеристиками:

  • открытость;
  • независимость от других языков (как естественных, так и алгоритмических);
  • независимость от конкретных API;
  • поддержка потоковой обработки;
  • реализация в виде текста.

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

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

18.1. Что такое XML и как с ним работать?

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

В то же время [12] универсальность текстового формата XML имеет и свою оборотную сторону. Прежде чем извлечь данные из XML-документа, вам необходимо выполнить синтаксический анализ текста и провести его декомпозицию на отдельные компоненты. Реализация всех этих процедур вручную представляет собой довольно нетривиальное занятие, которое способно поглотить все без исключения человеческие ресурсы. Одним из стандартных механизмов, которые позволяют значительно упростить жизнь, являются библиотеки XML-анализаторов.

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

  • извлечение общих сведений об анализируемом документе;
  • поиск в документе служебных конструкций (элементов, атрибутов, сущностей и т. д. [13]);
  • проверка синтаксической правильности документа в целом;
  • предоставление внешнего (пользовательского) интерфейса для доступа к документу.

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

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


// Открываем анализатор

$new_parser = xml_parser_create();
// подключаем к нему обработчики, ориентированные на нашу
// иерархическую структуру документа
xml_set_element_handler($new_parser, "startElement", "endElenient");

Существуют два основных класса анализаторов: верифицирующие и неверифицирующие. Первые проверяют структуру документа в соответствии с имеющимися схемами данных или описанием структуры документа DTD, а вторые этот процесс игнорируют.

18.2.XML и Expat

Пионером в области XML в мире UNIX стала библиотека Expat, которая сегодня либо является основой для построения XML-анализаторов, либо попросту входит в состав дистрибутивов других программных систем. В частности, в состав РНР 4 Expat включена изначально, а поддержка XML-анализатора включается по умолчанию.

18.2.1. Интерфейсы анализатора

При настройке анализатора XML в составе PHP-Машины вы столкнетесь с проблемой выбора одного из стандартов построения интерфейсов анализатора. На сегодняшний день используются два основных подхода к их построению — это DOM- и SAX-интерфейсы.

Первый из них основан на спецификации объектной модели документа DOM (Document Object Model), а второй — SAX (Simple API for XML) — появился в результате работы нескольких коллективов разработчиков XML.

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

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

Анализаторы SAX отражают другой подход к методологии обработки структурированного текста, который попросту можно выразить в виде поговорки — «пирог надо грызть с края», а если говорить формально — речь идет об анализаторе, ориентированном на события. Каждый раз, когда при разборе текста SAX-анализатор переходит в какое-либо новое состояние, то есть обнаруживает конструкцию XML- документа, фиксирует начало, конец объявлений элементов документа, просматривает DTD-правила или находит ошибку — он воспринимает это изменение как произошедшее событие. Для обработки обнаруженных данных производится вызов процедуры обработчика события, которой передаются сведения о «кусочке пирога» — текущем состоянии анализатора. При такой схеме прикладная программа является как бы «продолжением» анализатора — своеобразным «желудком», переваривающим кусочек за кусочком сообщения о новых фрагментах документа.

Если непредвзято сравнивать эти два подхода, то, конечно же, DOM-анализаторы выглядят более удобным и понятным способом обработки XML-документов. Однако очевидным недостатком DOM-анализатора является его расточительность по отношению к вычислительным ресурсам, ведь если документ имеет размер больше мегабайта, он все равно должен быть целиком загружен в память и останется там до конца работы с документом. Кроме того, пока документ не будет загружен целиком, получить доступ к его модели вы не сможете. Как следствие, DOM-анализаторы работают заметно медленнее, чем их основные конкуренты. Возможно, именно поэтому анализатор библиотеки Expat реализован именно как SAX — он позволяет обрабатывать XML-документ «на лету» формируя выходное представление по заданным критериям в процессе считывания файла.'

внимание
       Такой режим обработки называется потоковым и является предпочтительным с точки зрения минимизации времени отклика.

18.2.2. Обработчики событий Expat

Как уже указывалось выше, анализаторы класса SAX, к которым относится и встроенный в PHP-машину Expat, основаны на анализе и обработке событий, поэтому для настройки Expat на работу с конкретным типом документа вам необходимо установить несколько (обычно три) обработчиков событий с помощью функций, приведенных в табл. 18.1.

Таблица 18.1. Обработчики событий анализатора Expat
Функция Действие
xml_set_element_handler() Устанавливает обработчики событий, вызываемых при обнаружении XML-анализатором начальных и конечных тегов элементов. При этом функция устанавливает сразу два обработчика, для начального и для конечного тега (см. раздел 18.3.3)
xml_set_character_data_handler()Вызывается при обнаружении текстовых данных, которые находятся вне тегов XML-разметки. При этом никакие дополнительные пробелы не добавляются и не изымаются (см. раздел 18.3.4)
xml_set_processing_instruction_handler() Вызывается при обнаружении в теле XML-документа «инструкции обработки», используемой обычно для вызова внешних дополнительных программ. Следует иметь в виду, что для избежания конфликта с PHP-машиной, использующей такой же формат для выделения PHP-кода, необходимо использовать префикс <?xml>
xml_set_default_handler()Все, что не было распознано другими обработчиками, автоматически передается в этот. Как правило, он вызывается при обработке ссылок на DTD
xml_set_unparsed_entity_decl_handler() Вызывается при обработке сущностей типа NDATA
xml_set_notation_decl_handler() макроподстановок (notation)Вызывается при обслуживании объявлений
xml_set_external_entity_ref_handler()Обработчик вызывается в том случае, когда XML-анализатор обнаруживает ссылку на внешнюю по отношению к документу сущность. Это может быть ссылка на файл или URL-адрес

Из этих обработчиков чаще всего используются только первые два — обработчик тега и его содержимого, поэтому в этой главе я остановлюсь только на них. Остальные обработчики детально рассматриваются, например, в [14].

18.2.3. Чувствительность к регистру

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

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

18.2.4. Коды ошибок, возвращаемых анализатором

В табл. 18.2 приведены коды завершения работы анализатора, вызываемого функцией xml_parse (см. раздел 18.3.5), которые формирует встроенная подсистема анализа ошибок в XML-документе.

Таблица 18.2. Коды ошибок, возвращаемых анализатором
Код ошибки Значение
xml_error_noneУспешное завершение анализа документа
xml_error_no_memoryНедостаточно памяти для работы анализатора
xml_error_syntaxСинтаксическая ошибка в теле XML-документа
xml_error_no_elementsНе удалось обнаружить ожидаемый элемент разметки
xml_error_invalid_tokenНарушение целостности дерева документа. Не закрыт открытый ранее элемент
xml_error_unclosed_tokenНарушение целостности дерева документа. Не закрыт открытый ранее элемент
xml_error_partial_charДокумент не является правильно оформленным
xml_error_tag_mismatchНедопустимое использование тега разметки
xml_error_duplicate_attributeДублирование атрибута элемента
xml_errorjunk_after_doc_elementПосле закрытия элемента верхнего уровня в документе обнаружены теги разметки
xml_error_param_entity_refНедопустимая ссылка на параметры внешних сущностей
xml_error_undefined_entityПопытка использования неопределенной сущности
xml_error_recursive_entity_refРекурсивная ссылка на сущность
xml_error_async_entityПопытка использования асинхронной сущности
xml_error_bad_char_refСсылка на недопустимый код символа
xml_error_binary_entity_refСсылка на бинарную сущность
xml_error_attribute_external_entity_refСсылка на внешнюю сущность в атрибуте элемента
xml_error_misplaced_xml_piИнструкция обработки XML расположена не в начале внешней сущности
xml_error_unknown_encodingНеизвестная кодировка символов документа
xml_error_incorrect_encodingНедопустимая кодировка символов документа
xml_error_unclosed_cdata_sectionСекция CDATA не закрыта
xml_error_external_entity_handlingОшибка при обработке внешней сущности

18.2.5. Кодировка символов

Сразу же хочу отметить, что пока не вижу особого смысла в «переползании» на Unicode, который изначально встроен в XML. Подавляющая часть проектов, использующих XML, вполне может обойтись старой доброй КОИ-8, благо, как вы увидите ниже, никаких проблем это не вызывает. Но все равно, разобраться С вопросами представления данных в XML-анализаторе нам необходимо.

Прежде всего отметим, что с точки зрения XML-анализатора существуют две кодировки символов: входная (source encoding) и выходная (target encoding).

примечание
       Внутреннее представление документа в PHP-машине, по утверждению документации, всегда осуществляется в UTF-8, однако у меня этот факт вызывает серьезные сомнения. С моей точки зрения, это пока что декларация, а реально данные хранятся без преобразования в той кодировке, в которой они были считаны. Если, конечно, вы не начинаете манипулировать кодировкой в заголовке XML-документа.

Входная кодировка используется при анализе XML-документа. Эта кодировка должна задаваться при создании экземпляра анализатора и не может изменяться в ходе его работы. В настоящее время поддерживаются всего три типа кодировки: ISO-8859-1, US-ASCII и UTF-8, от которых нам ни холодно, ни жарко.

Первые две кодировки относятся к категории «однобайтовых», a UTF-8 позволяет использовать символы, представленные переменным количеством битов (до 21). По умолчанию используется входная кодировка ISO-8859-1.

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

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

Как же обходиться с кодировкой на практике? Я предпочитаю не указывать в XML- документах никакой кодировки и спокойно готовлю документы в КОИ-8. Поскольку я использую «Русский Apache» на платформе Linux, то вполне логичным и очевидным является выбор предпочтительной кодировки КОИ-8. А дальше в действиевступает механизм адаптации кодировки web-сервера. PHP-машина «перемалы- вает» теги, не обращая особого внимания на символьные данные, а потом уже Apache разбирается, кому из клиентов в какой кодировке должны быть представлены прообразованные в HTML выходные документы.

назад
далее

Сайт управляется системой uCoz