Что такое XML и как с ним работать?
XML и Expat
Функции XML-анализатора
Практический подход к анализу XML-документов
В этом разделе мы детально рассмотрим функции, необходимые для управления
работой XML-анализатора.
18.3.1. Создание экземпляра анализатора: xml_parser_create
1nt xm1_parser_create ([string encoding])
Функция создает экземпляр анализатора и возвращает его идентификатор. Необязательный аргумент encoding определяет входную кодировку, используемую
в процессе разбора документа. Поддерживаются следующие кодировки:
- ISO-8859-1 (используется по умолчанию);
- US-ASCII;
- UTF-8.
В случае ошибки возвращает false.
18.3.2. Анализатор внутри объекта: xml_set_object
void xml_set_object (int parser, object &оbjeсt)
Эта функция позволяет использовать анализатор XML внутри объекта. Все функции
обработчиков, устанавливаемые с помощью вызовов, перечисленных в табл. 18.1,
интерпретируются как методы этого объекта (см. листинг 18.1).
Листинг 18.1. Пример использования функции xml_set_object
<?php
// Создаем объект, в котором спрятан анализатор
class xml {
var $parser;
// Конструктор объекта: устанавливает обработчики
function xml() {
$this->parser = xml_parser_create();
xml_set_object($this->parser,&$this);
xm1_set_element_handler($this->parser,"tag_open","tag_close");
xml_set_character_data_handler($this->parser,"cdata");
}
// Метод, вызывающий анализатор XML
function parse($data) {
xml_parse($this->parser,$data);
}
// Обработчик события - открывающий тег элемента
function tag_open($parser,$tag,$attributes) {
var_dump($parser,$tag,$attributes);
}
// Обработчик текстовых данных внутри документа
function cdata($parser ,$cdata) {
var_dump($parser,$cdata);
}
// Обработчик события - закрывающий тег элемента
function tag_close($parser,$tag) {
var_dump($parser.$tag);
} // Конец определения класса xml
$xml_parser = new xml();
$xml_parser->parse("<A ID=\"hallo\">PHP</A>");
?>
18.3.3. xml_set_element_handler
int xml_set_e1ement_handler (int parser, string startElementHandler,
string endElementHandler)
Функция предназначена для установки обработчиков начального и конечного тегов элементов. Аргумент parser — это идентификатор анализатора, а аргументы
startElementHandler и endElementHandler должны представлять собой строки,
содержащие имена функций, определенных в PHP-машине на момент вызова функции xml_parse() (см. раздел 18.3.5).
Функция, имя которой передается через аргумент startElementHandler, должна
сопровождаться тремя параметрами:
startElementHandler (int parser, string name, array attribs)
parser Ссылка на XML-анализатор, вызвавший данный обработчик
name Имя элемента, для обработки которого вызван данный обработчик. В случае использования режима отключения чувствительности регистра (см. раздел 18.2.3) имя элемента представляется прописными буквами
attribs Ассоциативный массив, в котором ключами являются имена атрибутов, а значениями — их содержимое. Преобразование регистров символов имен атрибутов осуществляется таким же образом, как и для имен элементов. Значения атрибутов преобразованию не подвергаются.
Обработчик закрывающего тега элемента — функция endElementHandler— должна
сопровождаться двумя параметрами:
endElementHandler (int parser, string name)
parser Ссылка на XML-анализатор, вызвавший данный обработчик.
name Имя элемента, для обработки которого вызван данный обработчик. В случае использования режима отключения чувствительности регистра (см. раздел 18.2.3) имя элемента представляется прописными буквами.
Если вместо имени функции обработчика используется пустая строка или значение false, то установка соответствующего обработчика не производится либо отключается установленный ранее обработчик. Функция возвращает true, если установка обработчиков произведена успешно, и false, если аргумент parser не
является идентификатором анализатора.
18.3.4. xml_set_character_data_handler
int xml_set_character_data_handler (int parser, string handler)
Устанавливает функцию обработчика символьных данных (CDATA). Аргумент
parser должен содержать идентификатор анализатора XML, a handler — имя
функции обработчика, которая должна быть определена на момент вызова функции xml_parse() ( см. раздел 18.3.5).
Функция обработчика должна иметь вид:
handler (int parser, string data)
parser Содержит идентификатор анализатора XML
data Символьные данные, представленные в виде строки
Если вместо имени функции обработчика используется пустая строка или значение
false, то установка обработчика не производится либо отключается установленный ранее обработчик. Функция возвращает true, если установка обработчиков
произведена успешно, и false, если аргумент parser не является идентификатором анализатора.
18.3.5. Запуск анализатора: xml_parse
int xml_parse (int parser, string data [, int isFinal])
Функция предназначена для непосредственного выполнения анализа XML-документов с помощью одного из анализаторов, зарегистрированных в РНР-машине,
и вызывается со следующими аргументами:
parser Идентификатор используемого анализатора XML
data Фрагмент документа XML, подлежащего анализу. Вы можете анализировать документ по частям, вызывая xml_parse несколько раз с новыми данными, до тех пор пока не будет установлена переменная is Final, указывающая на завершающий фрагмент документа is Final Если эта переменная установлена и ее значение равно true, переданный функции фрагмент данных является последней частью разбираемого XML-документа
В процессе разбора XML-документа анализатор вызывает соответствующие обработчики (см. табл. 18.1) столько раз, сколько это необходимо по мере обнаружения и распознавания соответствующих фрагментов документа.
После завершения анализа фрагмента документа, переданного функции, xml_parse()
возвращает true, если анализ завершился без ошибок, или false, если провести
анализ документа без ошибок не удалось. В последнем случае вы можете получить информацию о причинах аварийного завершения с помощью функций
xml_get_error_code() (см. раздел 18.3.6), xml_error_stri ng() (см. раздел
18.3.7), xml_get_current_li ne_number () (см. раздел 18.3.8), xml_get_cur-
rent_column_number() (см. раздел 18.3.9) и xml_get_current_byte_index()
(см. раздел 18.3.10).
18.3.6. Считывание кода ошибки: xml_get_error_code
int xml_get_error_code (int parser)
Функция вызывается с целью выяснения причины аварийного завершения анализа документа с помощью xml_parse () (см. раздел 18.3.5). При вызове используется один аргумент — parser, который должен содержать идентификатор анализатора, запуск которого привел к ошибке.
Функция возвращает один из кодов ошибки, приведенных в разделе 18.2.4, или false,
если переданный ей аргумент не является идентификатором анализатора XML.
18.3.7. Сообщение об ошибке: xml_error_string
string xml_error_string (int code)
Аргументом функции является код ошибки, полученный с помощью функции
xml_get_error_code(). Результат вызова представляет собой текстовую строку,
содержащую описание ошибки, или false, если соответствующее коду описание
ошибки в PHP-машине отсутствует.
18.3.8. Текущая строка документа: xml_get_current_line_number
int xml_get_current_line_number (int parser)
Функция возвращает текущий номер строки анализируемого XML-документа.
Аргумент parser должен содержать идентификационный номер анализатора XML.
Если аргумент не указывает на зарегистрированный анализатор, функция возвращает false.
18.3.9. Текущее смещение в строке: xml_get_current_column_number
int xml_get_current_column_number (int parser)
Функция возвращает номер текущей позиции в строке, разбираемой XML-анализатором. Аргумент parser должен указывать на зарегистрированный анализатор
XML. Если же значению аргумента не соответствует ни один анализатор, функция возвращает false.
18.3.10. Смещение в буфере данных: xml_current_byte_index
int xml_get_current_byte_index (int parser)
Функция возвращает смещение в анализируемом XML-потоке данных относительно
начала буфера данных, над которым в данный момент времени работает анализатор.
Начальное смещение равно 0. Аргумент parser должен указывать на зарегистрированный в PHP-машине анализатор. Если это не так, функция возвращает false.
18.3.11. Преобразование в массив: xml_parse_into_struct
int xml_parse_into_struct (int parser, string data, array &values, array &index)
Эта функция преобразует разбираемый анализатором parser файл с XML-документом (data) в два массива, один из которых (index) содержит указатели на соответствующие значения в массиве values. Обратите внимание, что последние два
аргумента должны передаваться по ссылке (см. раздел 4.3).
В листинге 18.2 приведен небольшой пример, позволяющий разобраться со внутренней структурой массивов, генерируемых этой функцией.
Листинг 18.2. Преобразование документа с помощью функции xml_parse_into_struct
<ТIТLЕ>Преобразование документа в структуру</ТIТLЕ>
<body BGCOLOR="#FFFFFF"><FONT SIZE=+2>
<table border=l>
<tr><th>Индексный массив</th><th>Macив значений</th></tr>
<tr><td width=50%><pre>
<?php
$simple = "<para><note>simple note</note></para>";
$p = xml_parser_create() ;
xml_parse_into_struct($p,$simple,$vals,$index);
xml_parser_free($p);
print_r($index);
</pre></td><td width = 50%>
<pre>
<?
print_r($vals);
?>
</pre></td></tr>
</table>
<hr>
Как вы можете увидеть ниже, в первой строке мы создаем простейшую XML-структуру, которая состоит всего из двух элементов — para и note. Запустив эту программу на выполнение, вы получите таблицу, представленную на рис. 18.1.
Зачем же нужна эта функция и порождаемые ею структуры данных? Дело в том,
что при использовании библиотеки Expat, которая относится к категории SAX-
анализаторов, пользовательские обработчики событий усложняются по мере роста сложности структуры анализируемых документов XML. Собственно говоря,
именно этот факт и обусловливает потребность в DOM-анализаторах. Рассматриваемая нами функция, конечно, не создает объект в стиле DOM, но, тем не менее,
генерирует структуры, которые могут просматриваться в стиле a-la DOM, или,
попросту говоря, вы можете, проанализировав массивы, создать объекты, структура которых соответствует структуре XML-файла.
примечание
Фактически использование этой функции позволяет несколько приподнять пороговое
значение уровня сложности XML-документа, после достижения которого SAX-анализаторы резко теряют свою эффективность с точки зрения удобства использования.
Давайте рассмотрим еще один небольшой пример, заимствованный из документации к РНР 4, — базу данных аминокислот (moldb.xml) (листинг 18.3).
Листинг 18.3. База данных аминокислот: moldb.xml
<?xml version="1.0"?>
<moldb>
<molecule>
<name>Аланин</name>
<symbol>ALA</symbol>
<code>A</code>
<tуре>гидрофобная</tуре>
</molecule>
<molecule>
<nameе>Лизин</name>
<symbol>LYS</symbol>
<code>K</code>
<tуре>заряженная</tуре>
</molecule>
</moldb>
Рис. 18.1. Преобразование XML-документа с помощью функции
xml_parse_into_struct приводит к формированию двух массивов
А теперь взгляните на программу, которая осуществляет анализ этого документа
и генерацию соответствующих объектов (листинг 18.4).
Листинг 18.4. Формирование объектов в ходе анализа XML-документа moldb.xml
<titlе>Формирование объектов в ходе анализа ХМ1-документа</title>
<body BGCOLOR="#FFFFFF">
<?php
class AminoAcid {
van Sname; // название аминокислоты
var $symbol; // трехбуквенный код
var $code; // однобуквенный код
var $type; // гидрофобная, заряженная или нейтральная
function AminoAcid ($aa) {
foreach (Saa as $k=>$v)
$this->$k = $aa[$k] ;
}
}
function readDatabase($f ilename) {
// считываем базу данных из xml-файла
$data = implode(" " , file($f ilename)) ;
$parser = xml_parser_create() ;
xml_parser_set_option ( $parser, XML_OPTION_CASE_FOLDING,0) ;
xml_parser_set_option($parser,XML_OPTION_SKIP_WHITE,l) ;
xml_parse_into_struct ( $parser , $data, $values,$tags) ;
xml_parser_f ree(Sparser) ;
// пробегаем по сформированным структурам
foreach ($tags as $key=>$val) {
if ($key == "molecule") {
$molranges = $val;
// каждая пара записей в массиве
// обозначает соответственно
// нижнюю и верхнюю границы определения записи
for ($i=0; $i < count($molranges) ; $i+=2) {
$offset = $molranges[$i] + 1;
$len = $molranges[$i + 1] - $offset;
$tdb[] = parseMol(array_slice($values,
$offset, $len));
}
} else {
continue;
}
}
return $tdb;
}
function parseMol ($mvalues) {
for ($i=0; Si < count($mvalues) ; $i++)
$mol [$mvalues[$i] ["tag"] ] = $mvalues[$i] ["value"] ;
return new AminoAcid($mol) ;
>
$db = readDatabase("moldb.xml") ;
?>
<h3 align=right>Базa данных аминокислот</hЗ>
<hr>
<pre><font size=+l>
<?
print_r($db) ;
?>
</pre>
После выполнения этой программы в переменной $db содержится массив объектов класса AminoAcid, а на выходе вы получите результат, приведенный на
рис. 18.2.
Рис. 18.2. Массив объектов, полученный в результате анализа
XML-документа moldb.xml
18.3.12. Удаление анализатора: xml_parser_free
string xml_parser_free (int parser)
Поскольку анализатор занимает достаточно большой объем памяти, имеет смысл
после того, как пропадет необходимость его использования, удалить занимаемые
им структуры из оперативной памяти машины. Функция освобождения ресурсов имеет всего один аргумент — parser, который должен содержать идентификатор анализатора, который вы собираетесь удалить. Если операция удаления
завершена успешно, функция возвращает t rue, а если полученному ею аргументу не соответствует ни один из анализаторов в PHP-машине, функция вернет
false.
18.3.13. Настройка параметров: xml_parser_set_option
int xml_parser_set_option (int parser, int option, mixed value)
Функция предназначена для настройки отдельных режимов работы XML-анализатора. Принимает три аргумента: parser — идентификатор анализатора, option —
название параметра настройки, а также value — значение этого параметра. В случае ввода недопустимых значений функция возвращает false, если же установка
нового значения проведена успешно, возвращается true.
В настоящее время аргумент opti on может принимать следующие значения:
XML_OPTION_CASE_FOLDING (значения — true или false) — указывает, допускается ли автоматическое преобразование регистра тегов XML. По умолчанию преобразование разрешено.
ХМL_0PTI ON_TARGET_ENCODING (значение строковое) — устанавливает тип выходной кодировки символов, используемой XML-анализатором. По умолчанию выходная кодировка совпадает со входной2. В настоящее время к числу допустимых значений этого параметра относятся: ISO-8859-1, US-ASCII и UTF-8.
18.3.14. Считывание параметров: xml_parser_get_option
mixed xml_parser_get_option (int parser, int option)
Функция предназначена для считывания текущих настроек XML-анализатора. Она
принимает два параметра: parser, представляющий собой идентификатор анализатора, и option, указывающий, какой из параметров необходимо считать. Список параметров, поддерживаемых этой функцией, приведен выше (см. раздел
18.3.13).
Если при вызове указаны недопустимые аргументы, функция возвращает false.
В противном случае значением функции является значение соответствующего
параметра настройки.
18.3.15. Декодирование UTF-8: utf8_decode
string utf8_decode (string data)
Функция полагает, что переданный ей строковый аргумент содержит данные, представленные в кодировке UTF-8. При этом также предполагается, что это символы,
которые могут быть представлены в однобайтовой кодировке ISO-8859-1. Исходя
из этого и выполняется конвертирование форматов.
18.3.16. Кодирование UTF-8: utf8_encode
string utf8_encode (string data)
Эта функция выполняет преобразование исходной строки в кодировку UTF-8 и
возвращает результат преобразования. UTF-8 декларируется в последние годы как
стандартный механизм, используемый Unicode для преобразования многобайтных
кодов символов в байтовые потоки данных. Для нижней половины кодовой таблицы КОИ-8 (то есть для стандартного набора ASCII) преобразование происходит
совершенно прозрачно. Особенностью UTF-8 является его способность к самосинхронизации: программа, разбирающая поток UTF-8, в состоянии определить,
в каком месте начинается поток данных в этой кодировке. Кроме того, строки, записанные в UTF-8, могут подвергаться стандартным операциям и преобразовани-
ям: сортировке, сравнению, обрезке, перестановкам и т. д. В РНР поддерживается
преобразование символов в формат UNICODE вплоть до четырехбайтового формата, как показано в табл. 18.3.
Таблица 18.3. Кодировка UTF-8
Байты | Биты | Представление
| 1 | 7 | 0bbbbbbb
| 2 | 11 | 110bbbbb 10bbbbbb
| 3 | 16 | 1110bbbb 10bbbbbb 10bbbbbb
| 4 | 21 | 11110bbb 10bbbbbb 0bbbbbb 10bbbbbb
|
В таблице каждый символ «b» обозначает бит, который может использоваться для
хранения кода символа.
|