|
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Признак | Значение |
| ? | Ноль или ровно один экземпляр |
| * | Ноль или несколько экземпляров |
| + | Один или несколько экземпляров |
| Ровно один экземпляр | |
| | | Один из элементов |
| , | Перечисление элементов |
Если элемент будет содержать несколько вложенных элементов, их следует перечислить через запятую в определении родительского элемента:
<!ELEMENT recipe (title, description, ingredients, process)>
Поскольку признаки повторения не указаны, каждый тег должен встречаться ровно один раз.
Определение элемента уточняется при помощи логических операторов. Предположим, вы работаете с рецептами, в которые всегда входят макароны (pasta) с одним или несколькими типами сыра (cheese) или мяса (meat). В этом случае элемент ingredient определяется следующим образом:
<!ELEMENT ingredient (pasta+, (cheese | meat)+)>
Поскольку элемент pasta обязательно должен присутствовать в элементе ingredient, он указывается с признаком повторения +. Затем следует либо элемент cheese, либо элемент meat; мы разделяем альтернативы вертикальной чертой и заключаем их в круглые скобки со знаком +, поскольку в рецепт всегда входит либо одно, либо другое.
Существуют и другие разновидности определений элементов. Мы рассмотрели лишь простейшие случаи. Тем не менее, приведенного материала вполне достаточно для понимания примеров, приведенных в оставшейся части этой главы.
Объявления атрибутов
Атрибуты элементов описывают значения, связываемые с элементами. Элементы XML, как и элементы HTML, могут иметь ноль, один или несколько атрибутов. Общий синтаксис объявления атрибутов выглядит следующим образом:
<!ATTLIST имя_элемента имя_атри6ута1 тип_данных1 флаг1
Имя_элемента определяет имя элемента, включаемое в тег. Затем перечисляются атрибуты, связанные с данным элементом. Объявление каждого атрибута состоит из трех основных компонентов: имени, типа данных и флага, определяющего особенности данного атрибута. Вместо многоточия (...) могут быть расположены объявления других атрибутов.
Простое объявление атрибута уже встречалось нам в листинге 14.2:
<!ATTLIST recipe category CDATA #REQUIRED>
Тем не менее, как видно из приведенного общего определения, допускается одновременное объявление нескольких атрибутов. Допустим, в дополнение к атрибуту category вы хотите связать с элементом recipe дополнительный атрибут difficulty (сложность приготовления). Оба атрибута объявляются в одном списке:
<!ATTLIST recipe category CDATA #REQUIRED difficulty CDATA #REQUIRED>
Форматировать объявления подобным образом необязательно; тем не менее, многострочные объявления нагляднее однострочных. Кроме того, поскольку оба атрибута являются обязательными, тег reci ре не может ограничиться каким-нибудь одним атрибутом, он должен включать в себя оба атрибута сразу. Например, следующий тег будет считаться неверным: <recipe difficulty="hard">
Почему? Потому что в нем отсутствует атрибут category. Правильный тег должен содержать оба атрибута:
<recipe category="Italian" difficulty="hard">
Особые условия обработки атрибута описываются тремя флагами, перечисленными в табл. 14.2.
Таблица 14.2. Флаги атрибутов
|
Флаг |
Описание |
| #FIXED |
Во всех экземплярах элемента в документе атрибуту может присваиваться только одно конкретное значение |
| #IMPLIED |
Если атрибут не указан в элементе, используется значение по умолчанию |
| #REQUIRED |
Атрибут является обязательным и должен присутствовать во всех экземплярах элемента в документе |
Типы атрибутов
Атрибут элемента может объявляться с определенным типом. Типы атрибутов описаны далее.
Атрибуты CDATA
Очень часто атрибуты содержат общие символьные данные. Такие атрибуты называются атрибутами CDATA. Следующий пример уже встречался в начале этого раздела:
<!ATTLIST recipe category COATA #REQUIRED>
Атрибуты ID, IDREF и IDREFS
Идея однозначного представления данных (например, информации о пользователе или товаре, хранящейся в базе данных) посредством идентификаторов неоднократно встречалась в предыдущих главах книги. Идентификаторы также часто используются в XML, поскольку перекрестные ссылки между документами применяются не только в общих задачах обработки данных, но и в World Wide Web (гиперссылки).
Идентификаторы элементов присваиваются атрибуту ID. Допустим, вы хотите связать с каждым рецептом уникальный идентификатор. Соответствующий фрагмент DTD может выглядеть так:
<!ELEMENT recipe (title, description, ingredients, process)>
<!ATTLIST recipe recipe-id ID #REQUIRED>
<!ELEMENT recipe-ref EMPTY>
<!ATTLIST recipe-ref go IDREF #REQUIRED>
После этого объявление элемента recipe в документе может выглядеть так:
<recipe recipe-id="ital003">
<title>Spaghetti alla Carbonara</title>
Рецепт однозначно определяется идентификатором ital003. Следует помнить, что атрибут redpe-id относится к типу ID, поэтому ital003 не может использоваться в качестве значения атрибута recipe-id другого элемента, в противном случае документ будет считаться синтаксически неверным. Теперь допустим, что позднее вы захотели сослаться на этот рецепт из другого документа — скажем, из списка любимых рецептов пользователя. Именно здесь в игру вступают перекрестные ссылки и атрибут IDREF. Атрибуту IDREF присваивается идентификатор, используемый для ссылок на элемент, — по аналогии с тем, как URL используется для идентификации страницы в гиперссылке. Рассмотрим следующий фрагмент кода XML:
<favoriteRecipes>
<recipe-ref go="ital003">
</favoriteRecipes>
В процессе обработки документа XML элемент заменяется более наглядной ссылкой на рецепт с указанным идентификатором (например, названием рецепта). Вероятно, он будет отформатирован в виде гиперссылки, чтобы упростить переход к указанному рецепту.
Перечисляемые атрибуты
При объявлении атрибута можно перечислить все допустимые значения, принимаемые атрибутом. В нашем примере это было бы удобно, поскольку вы можете сразу определить список допустимых категорий. Приведенное выше объявление записывается в следующем виде:
<!ATTLIST recipe category (Italian | French | Japanese | Chinese) #REQUIRED difficulty (easy | medium | hard) #REQUIRED)
Обратите внимание: при использовании списков допустимых значений включать в объявление тип CDATA не нужно, поскольку все перечисленные значения относятся к формату CDATA.
Перечисляемые атрибуты со значением по умолчанию
Иногда бывает удобно объявить для атрибута значение по умолчанию. Скорее всего, вам уже приходилось делать это раньше при построении форм с раскрывающимися списками. Например, если большинство рецептов в вашей поваренной книге относится к итальянской кухне, атрибут recipe будет часто относиться к категории Italian. В этом случае категорию Italian можно назначить по умолчанию:
<!ATTLIST recipe category (Italian | French | Japanese | Chinese) "Itaian">
Если атрибут category не задан явно, по умолчанию ему присваивается значение Italian.
Атрибуты ENTITY и ENTITIES
Данные в документах XML не всегда являются текстовыми — документ может содержать и двоичную информацию (например, графику). На такие данные можно ссылаться при помощи атрибута entity. Например, в описании элемента description можно указать атрибут recipePicture с графическим изображением:
<!ATTLIST description recipePicture ENTITY #IMPLIED>
Также можно объявить сразу несколько сущностей, заменив ENTITY на ENTITIES. Значения разделяются пробелами.
Атрибуты NMTOKEN и NMTOKENS
Атрибуты NMTOKEN представляют собой строки из символов, входящих в ограниченный набор. Объявление атрибута с типом NMTOKEN предполагает, что значение атрибута соответствует установленным ограничениям. Как правило, значение атрибута NMTOKEN состоит из одного слова:
<!ATTLIST recipe category NMTOKEN #REQUIRED>
Можно объявить сразу несколько атрибутов, заменив NMTOKEN на NMTOKENS. Значения разделяются пробелами.
Объявления сущностей
Объявление сущности напоминает команду define в некоторых языках программирования, включая РНР. Ссылки на сущности кратко упоминались в предыдущем разделе «Знакомство с синтаксисом XML». На всякий случай напомню, что ссылка на сущность используется в качестве замены для другого фрагмента содержания. В процессе обработки документа XML все вхождения сущности заменяются содержанием, которое она представляет. Существует два вида сущностей: внутренние и внешние.
Внутренние сущности
Внутренние сущности напоминают строковые переменные, связывающие имя с фрагментом текста. Например, если вы хотите определить имя для ссылки на информацию об авторских правах, можно объявить сущность следующего вида:
<!ENTITY Copyright "Copyright 2000 YourCompanyName. All Rights Reserved.">
В процессе обработки документа все экземпляры &Соруright заменяются текстом «Copyright 2000 YourCompanyName. All Rights Reserved». Весь код XML в заменяющем тексте обрабатывается так, словно он присутствовал в исходном документе.
Внутренние сущности удобны в ситуациях, когда вы планируете использовать сущность в относительно небольшом количестве документов XML. При большом количестве документов лучше воспользоваться внешними сущностями.
Внешние сущности
Внешние сущности используются для ссылок на содержание, находящееся в другом файле. Сущности этого типа могут содержать текстовую информацию, но также могут ссылаться и на двоичные данные (например, графику). Возвращаясь к предыдущему примеру, допустим, что вы решили сохранить информацию об авторских правах в отдельном файле, чтобы упростить ее редактирование в будущем. Ссылка на созданный файл выглядит следующим образом:
<!ENTITY Copyright SYSTEM "http://yoursite.com/administer/copyright.xml">
При последующей обработке документа XML все ссылки &Соруright заменяются содержимым документа copyright.xml. Весь код XML в заменяющем тексте обрабатывается так, словно он присутствовал в исходном документе.
Внешние сущности также удобно использовать для ссылок на графические изображения. Например, если вы хотите включить в документ XML графический логотип, создайте внешнюю сущность:
<!ENTITY food_picture SYSTEM http://yoursite.com/food/logo.gif>
Как и в предыдущем примере, все ссылки &food_picture заменяются графическим изображением, на которое указывает ссылка. Поскольку данные являются двоичными, а не текстовыми, они не интерпретируются.
Ресурсы, посвященные XML
Хотя приведенного выше материала вполне достаточно для понимания базовой структуры документов XML, данное описание не является полным. Ниже приведены ссылки на ресурсы Интернета, содержащие более подробную информацию:
В оставшейся части главы рассказано о том, как использовать РНР для обработки документов XML. На первый взгляд задача кажется очень сложной (лексический анализ любых документов любого типа вызывает немало затруднений).
Но стоит познакомиться с базовой стратегией работы с XML в РНР, и все оказывается на удивление просто.
Для работы с XML в РНР используется пакет Джеймса Кларка (James Clark) Expat (XML Parser Toolkit) — cm. http://www.jclark.com/xml. Expat включается в поставку Apache 1.3.7 и более поздних версий, поэтому вам не придется специально загружать его, если вы используете свежую версию Apache. Чтобы воспользоваться функциональными возможностями XML в РНР, необходимо настроить РНР с ключом -with-xml.
Разработку Expat 2.0 в настоящее время ведет Кларк Купер (Clark Cooper). За дополни- тельной информацией обращайтесь по адресу http://expat.sourceforge.net.
На первый взгляд задача обработки данных XML на РHР (или на любом другом языке) выглядит устрашающе, но на самом деле большая часть работы выполняется за вас стандартными средствами РНР. Вам остается лишь определить новые функции для своих DTD и затем применить их в несложном процессе обработки кода XML.
Прежде чем переходить к рассмотрению функций РНР, предназначенных для работы с XML, необходимо познакомиться с основными компонентами документа XML. Это поможет вам лучше понять, почему эти функции являются незаменимой частью любой программы обработки XML-кода. На самом общем уровне документ XML содержит компоненты девяти видов:
Для эффективной обработки документов XML необходимо определить пользовательские функции-обработчики (handlers), обрабатывающие каждый из перечисленных компонентов. Определенные функции подключаются к процессу обработки XML стандартными средствами РНР. Общий процесс обработки кода XML в РНР состоит из пяти этапов:
Задача решается функцией xml_parser_free( ). Смысл всех перечисленных этапов разъясняется в следующем разделе.
Подключение пользовательских функций к обработке XML
В РНР существует восемь стандартных функций для регистрации пользовательских функций, обрабатывающих различные компоненты документов XML.
Следует помнить, что вы обязательно должны определить все пользовательские функции; в противном случае произойдет ошибка. В этом разделе перечислены все стандартные функции регистрации и приведены спецификации всех пользовательских функций.
xml_set_character_data_handler()
Функция регистрирует пользовательскую функцию для работы с символьными данными. Синтаксис:
int xml_set_character data_handler(int анализатор, string обработчик_символьных_данных)
Первый параметр определяет анализатор XML, а второй — имя пользовательской функции, используемой при обработке символьных данных. Определение функции-обработчика должно выглядеть так:
function обработчик_символьных_данных (int анализатор, string данные) {
...
}
Первый параметр определяет анализатор XML, а второй — символьные данные, подлежащие обработке.
xml_set_default_handler( )
Функция регистрирует пользовательскую функцию для всех незарегистрированных компонентов документа XML. В частности, к числу таких компонентов относятся пролог XML и комментарии. Синтаксис:
int xml_set_default_handler(int анализатор, string обработчик_по_умолчанию)
Первый параметр определяет анализатор XML, а второй — имя пользовательской функции, используемой по умолчанию. Определение функции-обработчика должно выглядеть так:
function обработчик_по_умолчанию (int анализатор, string данные) {
...
}
Первый параметр определяет анализатор XML, а второй — символьные данные, подлежащие обработке.
xml_set_element_handler( )
Функция регистрирует пользовательские функции для обработки открывающих и закрывающих тегов элементов. Синтаксис:
int xml_set_element_handler(int анализатор, string обработчик_открывающих_тегов, string обработчик_закрывающих_тегов)
Первый параметр определяет анализатор XML. Второй и третий параметры определяют имена функций, используемых для обработки, соответственно, открывающих и закрывающих тегов. Определение обработчика открывающих тегов должно выглядеть так:
function обработчик_открывающих_тегов (int анализатор, string имя_тега,
string атрибуты[ ]) {
...
}
Первый параметр определяет анализатор XML, второй — имя открывающего тега для анализируемого элемента, а третий содержит массив атрибутов соответствующего тега.
Обработчик закрывающих тегов определяется следующим образом:
function обработчик_закрывающих_тегов (int анализатор, string имя_тега) {
...
}
Первый параметр определяет анализатор XML, второй — имя закрывающего тега для анализируемого элемента.
xml_set_external_entity_ref_handler( )
Функция регистрирует пользовательскую функцию для обработки внешних ссылок на сущности. Синтаксис:
int xml_set_external_entity_ref_handler(int анализатор, string обработчик_внешних_ссылок)
Первый параметр определяет анализатор XML, а второй — имя пользовательской функции, используемой при обработке внешних ссылок. Определение функции-обработчика должно выглядеть так:
function обработчик_внешних_ссылок (int анализатор, string ссылка, string база. string системный_идентификатор, string открытый_идентификатор) {
...
}
Первый параметр определяет анализатор XML. Второй параметр определяет имя ссылки, четвертый — системный идентификатор ссылки на сущность, а пятый — открытый идентификатор ссылки. Третий параметр, база, в настоящее время не используется, однако его объявление все равно обязательно.
xml_set_notation_decl_handler ( )
Функция регистрирует пользовательскую функцию для обработки синтаксических объявлений. Синтаксис:
int xml_set_notation_decl_handler(int анализатор, string обработчик_синтаксических_обьявлений)
Первый параметр определяет анализатор XML, а второй — имя пользовательской функции, используемой при обработке синтаксических объявлений. Определение функции-обработчика должно выглядеть так:
function обработчик_синтаксических_обьявлений (int анализатор, string ссылка, string база, string системный_идентификатор, string открытый_идентификатор) {
...
}
Первый параметр определяет анализатор XML. Второй параметр определяет имя объявления, четвертый — системный идентификатор, а пятый — открытый идентификатор объявления. Третий параметр, база, в настоящее время не используется, однако его объявление все равно обязательно.
xml_set_object( )
Функция ассоциирует анализатор XML с некоторым объектом. Синтаксис:
void xml_set_object(int анализатор, object &о6ъект)
Первый параметр определяет анализатор XML, а второй содержит ссылку на объект, методы которого будут использоваться для обработки компонентов XML. Таким образом, функция xml_set_object связывает анализатор с объектом. Как правило, она вызывается в конструкторе объекта перед определениями функций-обработчиков:
class xmlDB {
VAR $xmlparser:
function xmlDB( ) {
$this->xmlparser = xml_parser_create();
// Связать анализатор с объектом
xml_set_object($this->xmlparser. &$this);
// Определить функции-обработчики
xml_set_element_handler($this->xmlparser,
"startTag","endTag");
xml_set_character_data($this->xmlparser,"characterData");
}
... Определения функций-обработчиков startTag. endTag. characterData и т.д. ...
} // class xmlDB
В порядке эксперимента попробуйте закомментировать вызов xml_set_object( ). Вы увидите, что при выполнении этого фрагмента выводятся сообщения об ошибках, в которых говорится о невозможности обращения к методам объекта.
xml_set_processing_instruction_handler( )
Функция регистрирует пользовательскую функцию для работы с Pi-инструкциями.
Синтаксис:
int xml_set_processing_instruction_handler(int анализатор, string обработчик_инструкций)
Первый параметр определяет анализатор XML, а второй — имя пользовательской функции, используемой при обработке Pi-инструкций. Определение функции-обработчика должно выглядеть так:
function обработчик_инструкций (int анализатор, string приложение, string инструкция) {
...
}
Первый параметр определяет анализатор XML, второй — имя приложения, выполняющего инструкции, а третий — инструкцию, передаваемую приложению.
xml_set_unparsed_entity_decl_handler( )
Функция регистрирует пользовательскую функцию для необработанных внешних ссылок на сущности. Синтаксис:
int xml_set_external_entity_ref_handler(int анализатор, string обработчик_внешних_ссылок)
Первый параметр определяет анализатор XML, а второй — имя пользовательской функции, используемой для обработки необработанных внешних ссылок. Определение функции-обработчика должно выглядеть так:
function обработчик_внешних_ссылок (int анализатор, string сущность, string база, string системный_идентификатор. string открытый_идентификатор, string имя_объявления) {
...
}
Первый параметр определяет анализатор XML. Второй параметр определяет имя ссылки, четвертый — системный идентификатор ссылки на сущность, а пятый — открытый идентификатор ссылки. Третий параметр, база, в настоящее время не используется, однако его объявление все равно обязательно. Наконец, последний параметр определяет имя синтаксического объявления.
На этом завершается наше краткое знакомство с обработчиками и функциями регистрации. Впрочем, для эффективной обработки документов XML вам понадобятся и другие функции. В следующем разделе представлены остальные функции РНР, связанные с обработкой кода XML.
Хотя реализация всех функций-обработчиков не обязательна (документы XML не обязаны содержать элементы всех типов), по крайней мере три функции должны присутствовать во всех сценариях, работающих с XML.
xml_parser_create( )
Перед обработкой документа XML необходимо предварительно создать анализатор. Синтаксис:
int xml_parser_create([stnng кодировка])
Необязательный параметр определяет кодировку исходного текста. В настоящее время поддерживаются три варианта кодировки:
По аналогии с тем, как функция fopen( ) возвращает манипулятор открытого файла, функция xml_parser_create( ) также возвращает манипулятор, используемый для вызова различных функций в процессе обработки XML. При одновременной обработке нескольких документов можно создать сразу несколько анализаторов.
xml_parse()
Функция xml_parse( ) выполняет обработку документа XML. Синтаксис:
int xml_parse(int анализатор, string данные [int завершение])
Первый параметр определяет анализатор XML (используется значение, возвращаемое при вызове xml_parser_create( )). Если необязательный параметр завершение равен TRUE, передаваемый фрагмент данных является последним. Как правило, это происходит при достижении конца обрабатываемого файла.
xml_parser_free( )
Функция освобождает ресурсы, выделенные для работы анализатора. Синтаксис:
int xml_parser_free(int анализатор)
Параметр функции определяет анализатор XML.
В РНР также существуют другие функции, упрощающие процесс обработки кода XML.
utf8_decode( )
Функция преобразует данные в кодировку ISO-8859-1. Предполагается, что преобразуемые данные находятся в кодировке UTF-8. Синтаксис:
string utf8_decode(string данные)
Параметр данные содержит преобразуемые данные в кодировке UTF-8.
utf8_encode( )
Функция преобразует данные из кодировки ISO-8859-1 в кодировку UTF-8. Синтаксис:
string utf8_decode(string данные)
Параметр данные содержит преобразуемые данные в кодировке ISO-8859-1.
xml_get_error_code( )
Функция xm1_get_error_code( ) получает код ошибки, возникшей в процессе обработки XML. Код ошибки передается функции xml_error_string( ) (см. ниже) для интерпретации. Синтаксис:
int xml_error_code(int анализатор)
Параметр функции определяет анализатор XML. Пример использования приведен ниже, в описании функции xml_get_current_line_number( ).
xml_error_string( )
Ошибкам, возникающим в процессе анализа кода XML, присваиваются числовые коды. Функция xml_error_string( ) возвращает текстовое описание ошибки по ее коду. Синтаксис:
string xml_error_string(int код)
В параметре функции передается код ошибки (вероятно, полученный при вызове функции xml_get_error_code( )). Пример использования функции приведен ниже, в описании функции xml_get_current_line_number( ).
xml_get_current_line_number( )
Функция возвращает номер текущей строки, обрабатываемой анализатором XML. Синтаксис:
int xml_get_current_line_number(int анализатор)
Параметр функции определяет анализатор XML. Пример использования функции:
while ($line - fread($fh. 4096)) :
if (! xml_parse($xml_parser. $line. feof($fh)));
$err_string - xml_error_string(xml_get_error_code($xml_parser));
$line_number - xml_get_current_line_number($xml_parser);
print "Error! [Line Sline_number]: $err_string";
endif;
endwhile;
Например, если ошибка была обнаружена в шестой строке файла, определяемого манипулятором $fh, сообщение будет выглядеть примерно так:
Error! [Line 6]:mi snatched tag
xml_get_current_column_number( )
Функция xml_get_current_colunin_number( ) может использоваться в сочетании с xml_get_current_line_number( ) для определения точного местонахождения ошибки в документе XML. Синтаксис:
int xml_get_current_column_number(int анализатор)
Параметр функции определяет анализатор XML. Давайте усовершенствуем предыдущий пример:
while ($line = fread($fh. 4096)) :
if (! xml_parse($xml_parser, $line, feof($fh))):
$err_string = xml_error_string(xml_get_error_code($xml_parser));
$line_number = xml_get_current_line_number($xml_parser);
$column_number = xml_get_current_column_number($xml_parser)
print "Error! [Line $line_nuimber, Column $column_number]: $err_string";
endif;
endwhile;
Например, если ошибка была обнаружена в шестой строке файла, определяемого манипулятором $fh, сообщение будет выглядеть примерно так:
Error! [Line 6 Column 2]:mismatched tag
В настоящее время в РНР поддерживаются два параметра, влияющих на работу анализатора XML:
Для получения текущих значений и модификации этих параметров применяются, соответственно, функции xml_parser_get_option( ) и xml_parser_set_option( ).
xml_parser_get_option( )
Функция xml_parser_get_option( ) получает текущее значение параметра анализатора XML. Синтаксис:
int xml_parser_get_option(int анализатор, int параметр)
Первый параметр функции определяет анализатор XML, а второй — имя интересующего вас параметра. Пример:
$setting = xml_parser_get_option($xml_parser, XML_OPTION_CASE_FOLDING);
print "Case Folding: $setting";
Если параметру XML_OPTION_CASE_FOLDING не присваивалось другое значение, функция вернет значение по умолчанию. В этом случае будет выведен следующий результат:
Case Folding: 1
xml_parser_set_option( )
Функция xml_parser_set_option() задает значение параметра анализатора XML. Синтаксис:
int xml_parser_set_option(int анализатор, int параметр, mixed значение)
Первый параметр функции определяет анализатор XML, второй — имя интересующего вас параметра, а третий — его новое значение. Пример:
$setting = xml_parser_set_option($xml_parser, XML_OPTION_TARGER_ENCODING."UTF-8"):
В результате выполнения этой команды выходная кодировка документа изменяется с ISO-8859-1 на UTF-8.
Предположим, у вас имеется документ XML bookmarks.xml, содержащий список ссылок. Он выглядит примерно так:
<?xml version="1.0"?>
<website>
<title>Epicurious</title>
<url>http://www.epicurious.com</url>
<description>
Epicurious is a great online cooking resource, providing tutorials.
recipes, forums and more.
</description> </website>
Допустим, вы хотите преобразовать bookmarks.xml и вывести его содержимое в формате, совместимом с форматом браузера вашего компьютера. Программа, приведенная в листинге 14.3, преобразует файл к нужному формату.
Листинг 14.3. Преобразование XML в HTML
Class XMLHTML {
VAR $xmlparser: VAR $tagcolor ="#800000";
VAR $datacolor ="#0000ff";
function XMLHTML( ) {
$this->xmlparser = xml_parser_create();
xml_set_object($this->xmlparser. &$this);
xml_set_element_handler($this->xmlparser, "startTag", "endTag");
xml_set_character_data_handler($this->xmlparser. "characterData");
}
// Функция отвечает за обработку всех открывающих тегов.
function startTag($parser, $tagname, $attributes) {
GLOBAL $tagcolor;
print "<font size=\"-2\" color=\"$this->tagcolor\" face=\"arial,
verdana\ ">&1 t ; $tagname> ; </f ont> <br>" ;
// Функция отвечает за обработку всех символьных данных.
function characterData($parser. $characterData) {
GLOBAL $datacplor;
print "<font size=\"-2\" color=\"$this->datacolor\" face=\"arial,
verdana\ "> $characterData</font> <br>";
// Функция отвечает за обработку всех закрывающих тегов.
function endTag(Sparser, $tagname) {
GLOBAL Stagcolor;
print "<font size=\"-2\" color=\"$this->tagcolor\" face=\"arial, verdana\"></
$tagname></font> <br>";
}
function.parse($fp) {
// xml_parse($this->xm1parser,$data);
// Обработать файл XML
while ( $line = fread($fp. 4096) ) :
// При возникновении ошибки прервать обработку // и вывести сообщение об ошибке.
if ( ! xml_parse($this->xmlparser, $line, feof($fp))) :
die(sprintf("XML error: %s at line %d",
xml_error_sthng(xml_get_error_code($this->xmlparser)),
xml_get_curren_line_number($this->xml parser)));
endif;
endwhile;
}
}
// Открыть файл XML для обработки
$xml_file = "bookmarks. xml";
$fp = f open ($xml_flie, "r");
// Создать новый объект
$xml_parser = new XMLHTML;
// Обработать $xml_file
$xml_parser->parse($fp);
?>
В результате преобразования файл bookmarks.xml выводится в браузере в следующем виде:
<WEBSITE>
<TITLE>
Epicurious
</TITLE>
<URL>
http : //www.epicurious.com
</URL>
<DESCRIPTION>
Epicurious is a great online cooking resource,
providing tutorials, recipes, forums and more.
</DESCRIPTION>
</WEBSITE>
Конечно, результат не такой уж впечатляющий — мы всего лишь добились, чтобы файл XML отображался в браузере. Внеся небольшие изменения в листинг 14.3, можно преобразовать URL в работающие гиперссылки, оформить данные между парой тегов <TITLE>...</TITLE> жирным шрифтом и т. д. Как видно из листинга 14.3, я использую шрифт двух разных цветов, чтобы продемонстрировать возможность форматирования текста в браузере.
В этой главе мы познакомились с XML и различными функциями РНР, предназначенными для обработки документов в формате XML. Поскольку основной темой книги является РНР, я описал лишь одну из трех спецификаций стандарта XML и не упомянул о том, как работают XSL и XLL. Конечно, полноценное отделение содержания от представления требует использования всех трех компонентов или по меньшей мере XML и XSL.
К сожалению, на момент написания книги РНР еще не обладал возможностями, которые бы позволяли работать с XML исключительно средствами РНР. Конечно,
возможности РНР продолжают расширяться, и в будущем эта проблема обязательно будет решена.
Особого внимания в этой области заслуживает XSL-процессор Sablotron, разработанный компанией Ginger Alliance Lts. (http://www.gingerall.com). 12 октября 2000 года было объявлено о том, что РНР 4.03 отныне распространяется с модулем расширения Sablotron для платформ Linux и Windows. Обязательно проследите за дальнейшим развитием событий.
В этой главе был изложен довольно обширный материал, касающийся XML и возможностей обработки кода XML в РНР. Глава начинается с краткой истории языков разметки. Читатель знакомится с XML и его основными преимуществами, после чего приводится сводка синтаксических конструкций языка. Оставшаяся часть главы посвящена стандартным функциям РНР для работы с кодом XML. В завершение приводятся примеры использования РНР для обработки и вывода данных XML. В частности, рассматриваются следующие вопросы:
В главе 15 рассматриваются две перспективные технологии, JavaScript и СОМ (Component Object Model), и возможности их использования в РНР.
|