|
Навигация
|
Главная » Xml Синтаксический анализ XML в PHP (исходники)Источник: IBM developerWorks Россия Эллиотт Расти Хэролд PHP 5 представил XMLReader , новый класс для чтения расширяемого языка разметки (XML). В отличие от простого XML или объектной модели документов (DOM) XMLReader работает в потоковом режиме. То есть он считывает документ от начала до конца. Можно начать работать с содержимым документа в его начале, перед тем как вы увидите его окончание. Это делает работу очень быстрой, эффективной и очень экономной с точки зрения затрат памяти. Чем больше размер документов, которые необходимо обрабатывать, тем это важнее.
XMLReader - в большей мере принимающий парсер (pull parser), чем передающий парсер (push parser). Это означает, что программа находится под контролем. Вместо того, чтобы парсер сообщал вам, что он видит, когда он это видит; вы указываете парсеру, когда необходимо переходить к следующему фрагменту документа. Вы запрашиваете контент вместо того, чтобы реагировать на него. Другими словами, это можно представить так XMLReader - это реализация конструктивного шаблона Iterator (итератор), а не конструктивного шаблона Observer (наблюдатель).Образец задачиДавайте начнем с простого примера. Представьте, что вы пишете PHP-скрипт, который получает XML-RPC запросы и генерирует ответы. Точнее, представьте, что запросы выглядят, как показано в листинге 1. Корневой элемент документаmethodCall , в котором содержатся элементы methodName и params . Название метода - sqrt . Элемент params содержит один элемент param , включающий в себя double - число, квадратный корень которого нужно извлечь. Области имен не используются.Листинг 1. Запрос XML-RPC
Вот что должен делать PHP-скрипт:
Давайте рассмотрим это шаг за шагом. Инициализация парсера и загрузка документаПервым шагом является создание нового объекта парсера. Сделать это просто:
Далее нужно ввести некоторые данные для разбора. Для XML-RPC это - необработанное тело запроса по протоколу HTTP. Затем эта строка может быть передана функции XML() программы считывания:
Можно проанализировать любую строку, откуда бы вы ее ни взяли. Например, это может быть строковая литеральная константа в программе или содержимое файла. Также можно загрузить данные с внешнего URL при помощи функции open() . К примеру, следующая инструкция готовит один из Atom-каналов для разбора:
Откуда бы вы ни взяли исходные данные, программа чтения теперь установлена и готова выполнять анализ. Чтение документаФункцияread() перемещает парсер к следующему маркеру. Самый простой подход заключается в выполнении итераций цикла while по всему документу:
По окончании закройте парсер, чтобы освободить ресурсы, которые он занимает, и перенастройте его для следующего документа:
Внутри цикла парсер помещается в определенном узле: в начале элемента, в конце элемента, в текстовом узле, в комментарии и так далее. Следующие свойства позволяют узнать, что парсер просматривает в данный момент:
nodeType для определения того, что просматривается, и выдачи соответствующего ответа. В листинге 3 показан простой цикл while , который использует эти функции для вывода того, что он просматривает. В листинге 4 показан результат работы этой программы, когда ей на вход подается листинг 1.Листинг 3. Что видит парсер
Большая часть программ не так универсальна. Они принимают входные данные в особой форме и обрабатывают их определенным образом. В примере XML-RPC нужно считать только один параметр из входных данных: элемент double , который должен быть только один. Чтобы это сделать, найдите начало элемента с именем double :
У этого элемента также есть единственный текстовый дочерний узел, который можно считывать, перемещая парсер к следующему узлу:
Здесь функция respond() создает ответ XML-RPC и отправляет его клиенту. Однако, прежде чем я покажу это, необходимо рассказать еще кое-что. Нет никакой гарантии того, что элементdouble в документе запроса содержит только один текстовый узел. Он может содержать несколько узлов, а также комментарии и операторы. Например, это может выглядеть следующим образом:
double , объединять их в цепочку и только затем конвертировать результат в double . Необходимо избегать любых комментариев или других возможных нетекстовых узлов. Это немного сложнее, но, как показано в листинге 5, не слишком.Листинг 5. Суммируйте весь текстовый контент элемента
Пока весь остальной контент документа можно игнорировать. (Позже я продолжу описание обработки ошибок). Создание ответаКак следует из имени,XMLReader предназначен только для чтения. Соответствующий класс XMLWriter сейчас находится в разработке, но еще не готов. К счастью, писать XML гораздо легче, чем его считывать. Во-первых, следует задать тип носителя ответа, используя функцию header() . Для XML-RPC это application/xml . Например:
Содержание обычно легко отображается прямо на странице, как показано в функции respond() листинга 6.Листинг 6. Отображение XML
Можно даже вставить буквенные части ответа прямо в страницу PHP, так же, как это было бы реализовано в HTML. Данная технология показана в листинге 7. Листинг 7. Буквенный XML
Обработка ошибокДо настоящего момента подразумевалось, что входной документ оформлен корректно. Однако этого никто не может гарантировать. Как любой парсер XML,XMLReader должен прекратить обработку, как только обнаружит ошибку оформления. Если это происходит, то функция read() возвращает false (ложь).Теоретически, парсер может обрабатывать данные до первой обнаруженной им ошибки. В моих экспериментах с маленькими документами, однако, он сталкивается с ошибкой почти сразу. Лежащий в основе парсер предварительно анализирует большой участок документа, кэширует его, а затем выдает его по частям. Таким образом, он обычно определяет ошибки на предварительном этапе. В целях безопасности лучше не берите на себя ответственность за то, что сможете выполнить анализ контента до первой ошибки оформления. Более того, не предполагайте, что не увидите никакого контента до ошибки парсера. Если нужно принять только полные, корректно оформленные документы, то убедитесь, что скрипт не делает ничего необратимого до самого конца документа. Если парсер обнаруживает ошибку в оформлении, то функция read() отображает сообщение об ошибке, аналогичное представленному (если настроен подробный отчет об ошибке, как и должно быть на сервере разработки):
Вы, возможно, не захотите копировать отчет на страницу HTML, представляемую пользователю. Лучше фиксировать сообщение об ошибке в переменной среды $php_errormsg . Для этого нужно включить опцию конфигурации track_errors в файле php.ini:
По умолчанию опция track_errors отключена, что явно указано в php.ini, поэтому не забудьте изменить эту строку. Если вы добавите строку, показанную выше, в начало php.ini, то строка track_errors = Off , которая написана ниже, заменит ее.Эта программа должна посылать ответы только на полные, правильно оформленные входные данные. (Также достоверные, но об этом позже.) Таким образом, нужно подождать завершения анализа документа (выход из цикла while ). Теперь проверьте, изменилось ли значение $php_errormsg . Если нет, то документ оформлен корректно, и будет отправлено ответное сообщение XML-RPC. Если переменная задана, то это означает, что документ оформлен некорректно, и будет отправлен сигнал о сбое XML-RPC. Также сигнал о сбое отправляется, если запрашивается квадратный корень отрицательного числа. Смотрите листинг 8.Листинг 8. Проверка корректного оформления
Здесь приведена упрощенная версия общего шаблона обработки потоков XML. Парсер заполняет структуру данных, в соответствии с которой выполняются действия, когда документ заканчивается. Обычно структура данных проще, чем сам документ. Здесь структура данных особенно простая: единственная строка. Валидация
XMLReader поддерживает язык описания схемы RELAX NG; в листинге 9 показана простая схема RELAX NG для данной конкретной формы запроса XML-RPC.Листинг 9. Запрос XML-RPC
Схему можно добавить непосредственно в PHP-скрипт в виде строкового литерала при помощи setRelaxNGSchemaSource() или считать ее из внешнего файла или URL с помощью setRelaxNGSchema() . Например, при условии, что содержимое листинга 9 записано в файле sqrt.rng, схема будет загружаться следующим образом:
Выполните это прежде , чем начнете анализировать документ. Парсер сравнивает документ со схемой во время чтения. Чтобы проверить, является ли документ достоверным, вызовите функцию isValid() , которая возвращает значение true, если документ валиден (на данном этапе) и false в противном случае. В листинге 10 показана полная логически завершенная программа, содержащая обработку всех ошибок. Программа должна принимать любые достоверные входные данные и возвращать правильные значения и отклонять все неправильные запросы. Я также добавил метод fault() , который отправляет сигнал о сбое XML-RPC, если что-то идет не так.Листинг 10. Полная серверная часть извлечения квадратного корня XML-RPC
АтрибутыАтрибуты не видны при нормальном выполнении анализа. Чтобы считать атрибуты, необходимо остановиться в начале элемента и запросить конкретный атрибут либо по имени, либо по номеру.Передайте имя атрибута, значение которого необходимо найти в текущем элементе, функции getAttribute() . К примеру, следующая конструкция запрашивает атрибут id текущего элемента:
Если атрибут - в пространстве имен, например, xlink:href , то вызовите getAttributeNS () и передайте локальное имя и URI пространства имен в качестве первого и второго аргументов соответственно (префикс не имеет значения). Например, данная инструкция запрашивает значение атрибута xlink:href в пространстве имен http://www.w3.org/1999/xlink/:
Если атрибут не существует, то оба метода возвратят пустую строку. (Это неправильно, так как они должны вернуть null. Данная реализация усложняет возможность различать атрибуты, значение которых - пустая строка, и те, которые вообще отсутствуют.)
moveToNextAttribute() , когда считывающая часть установлена на элементе. Если парсер находится на узле атрибута, то можно считать его имя, пространство имен и значение при помощи тех же свойств, которые использовались для элементов. Например, следующий фрагмент кода распечатывает все атрибуты текущего элемента:
Очень необычно для XML API то, что XMLReader позволяет считывать атрибуты либо с начала, либо с конца элемента. Чтобы избежать двойного отсчета, важно убедиться, что типом узла является XMLReader::ELEMENT , а не XMLReader::END_ELEMENT , у которого тоже могут быть атрибуты.ЗаключениеXMLReader - полезное дополнение к инструментарию программиста PHP. В отличие от SimpleXML это полный парсер XML, который обрабатывает все документы, а не только некоторые из них. В отличие от DOM он может обрабатывать документы большие, чем доступная память. В отличие от SAX он устанавливает контроль над программой. Если PHP-программам нужно принимать входные данные XML, то стоит всерьез задуматься об использовании XMLReader .Вероотступник Geronimo: Что нового в OpenEJB 3.0 (исходники). Освоение Ajax: Часть 8. Использование XML в запросах и ответах (исходники). pureXML в DB2 9: Каким способом запрашивать XML-данные? (исходники). XML в Oracle - это очень просто. Программирование на XML для DB2: Часть 1. Понимание модели данных XML (исходники). Главная » Xml |
© 2024 Team.Furia.Ru.
Частичное копирование материалов разрешено. |