Учебник по основам PHP

         

XML-интерпретация


XML (extensible Markup Language) — формат обмена структурированными данными в пространстве web; стандарт, определенный Консорциумом World Wide Web (W3C). Информацию о XML и связанных технологиях можно получить по адресу http://www.w3.org/XML/. Для понимания материала главы необходимо разбираться в синтаксисе XML

Для работы с документами XML используются два способа.

  1. Использование объектной модели документа (DOM), которая удобна для работы с документом в целом, но расходует больше ресурсов.
  2. Интерпретация документа на основе модели событий, удобная при однократном просмотре документа и менее требовательная к ресурсам (что важно при работе с объемными документами).

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

  • Устанавливаются функции обработки элементов документа различного типа (например, маркеров, данных,-инструкций и т. д.).
  • Инициализируется и запускается интерпретатор, который последовательно просматривает документ и запускает соответствующие обработчики данных.
  • Функции-обработчики определенным образом обрабатывают передаваемые им фрагменты документа.


Заметьте, что интерпретатор предназначен для обработки документа, но не для его проверки; документ должен соответствовать грамматике XML (и правилам DTD).

В РНР интерпретатор XML использует библиотеку expat (ее также использует Apache-1.3.9 и последующие версии), см.: http://www. jclark.com/xml/. Скомпилировать РНР с поддержкой expat можно, используя параметр --with-xml.

Для документов поддерживаются кодировки US-ASCII, ISO-8859-1 (по умолчанию), UTF-8 (UTF-16 не поддерживается). Разделяют исходную и целевую кодировки. Исходная кодировка — это набор символов документа (ее можно изменять в процессе интерпретации). (Внутри РНР символы всегда хранятся в кодировке UTF-8, позволяется использовать символы размером до 21 бита.) В функции-обработчики данные передаются в целевой кодировке (для всех типов данных). При нахождении в документе-символа, не соответствующего исходной кодировке, выдается ошибка; а если символ не может быть представлен в целевой кодировке, то он заменяется на знак вопроса.

Интерпретация (по умолчанию) не учитывает регистр имен тегов, то есть в функции обработки символы передаются преобразованными к верхнему регистру. Для отключения этого используйте:

xml__parser_set_option($xml_parser. XML_OPTION_CASE_FOLDING. 0);

Для интерпретатора можно определить следующие виды функций-обработчиков:

  • xml_set_element_handler() — обработчики начальных и конечных тегов;
  • xml_set_character_data_handler() — текст между тегами (с учетом пробелов);
  • xml set_processing_instruction_handler() — инструкции обработки (например, <?php ?> и подобные им; инструкция <?xml ?> зарезервирована);
  • xml_set__default_handler() — обработчик по умолчанию, используемый при невозможности использования иного обработчика;
  • xm"l_set_unparsed_entity_decl_handler() — обработчик необрабатываемых (NDATA) данных;
  • xml_set_notation_decljiandler() — обработчик нотаций;
  • xml_set_external_entity_ref_handler() — обработчик внешних ссылок.

Коды ошибок

Модулем интерпретатора XML определяются следующие константы кодов ошибок (возвращаемые функцией xml_parse()):

  • XML_ERROR_NONE;
  • XML_ERROR_NO_MEMORY;
  • XML_ERROR_SYNTAX;
  • XML ERRORJO ELEMENTS;
  • XML_ERROR_INVALIDJOKEN;
  • XML_ERROR_UNCLOSED_TOKEN;
  • XML_ERROR_PARTIAL_CHAR;
  • XMLJRRORJAG MISMATCH;
  • XML_ERROR_DUPLICATE_ATTRIBUTE;
  • XML_ERROR_JUNK_AFTER_DOC_ELEMENT;
  • XML_ERROR_PARAM_ENTITY_REF;
  • XML_ERROR_UNDEFINED_ENTITY;
  • XML_ERROR_RECURSIVE_ENTITY_REF;
  • XMLJRROR_ASYNC_ENTITY;
  • XML_ERROR_BAD_CHAR_REF;
  • XML_ERROR_BINARY_ENTITY_REF;
  • XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF;
  • XML_ERROR_MISPLACED_XML_PI;
  • XMLJRRORJJNKNOWN ENCODING;
  • XML_ERRORJNCORRECT_ENCODING;
  • XML_ERROR_UNCLOSED_CDATA_SECTION;
  • XML_ERROR_EXTERNAL_ENTITY_HANDLING.

Примеры

Следующие примеры демонстрируют возможности интерпретации документов XML.

Распечатка структуры XML документа

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

Sfile = "data.xml": Sdeptti = аггау()
function startElement($parser. $name. Sattrs)
{ global Sdepth:
for ($1 = 0. $1 < $depth[$parser]; $i++) { print "". }
print "$name\n": $depth[$parser]++; }
function endElement($parscr. $name)
{ global $depth- $depth[$parser]--; }
$xml_parser = xml_parser_create().
xml__set_element_nandler
($xml_parser. "startElement", "endElement"):
if (!($fp = fopen($file. "r"») {
dieC'could not open XML input")
while «data = fread($fp. 4096)) {
ll(!xml_parse($xml_parser, $data. feof($fp)))
{ die(sprintf("XML error: Xs at line id".
xml_error_string(xml_get_error_code($xml_parser)),
xml_get_current_l ine__number($xml_parser)));
xml_parser_free($xml на-se"):

Преобразование тегов XML в HTML

$file = "data xml '. $jndp_array = arrayt
"BOLD" > "B". "EMPHASIS" => "I".
"LITERAL" => "TT' );
function startElement($parset . $пате. Sattrs)
{ global $map_array; if (ShtTiltag = $map_array[$namej)
{ print "<$htmltag>'. function endElanenttSparser. $namp)
{ global $mao_array. if (Shtmltag - $map_array[$name]) (
print "</$htmltag>"; } } function characterData(Sparser. $data) {
print Sdata: } $xml_parser = xml_parser_create();
// отключить чувствительность к регистру
xml_parser_set_option
($xml_parser. XML_OPTION_CASE_FOLDING. TRUE):
xml_set_element_handler
($xml_parser. "startElement". "endElement");
xml_set_character_data_handler
($xml_parser. "characterData");
if (!($fp = fopen($file. "r")))
{ dieC'could not open XML input"); } while (Sdata = fread(Sfp. 4096)) {
if (!xml_parse($xml_parser. Sdata. feof($fp)))
{ die(spnntf("XML error: £s at line %u".
xml_error_string(xml_get_error_code
(Sxml_parser)). xml_get_current_line_number($xml_parser))): }
} xml_parser_free($xml_parser).

Обработка специальных конструкций XML

Пример демонстрирует обработку подключенных внешних файлов и инструкций обработки. Использует при выводе разметку HTML.

$file = "xmltest.xml"; function trustedFile(Sflle) {
// исполнять код можно только в
собственных файлах if (!eregi(""([a-z]+)://". Sfile)
&& fileowner(Sfile) == getmyuid()) ( return TRUE; }
return FALSE. }
function startElement(Sparser. $name. Sattribs) {
print "&lt;<font color=\"#OOOOcc\">Sname</font>"
: if (sizeof(Sattnbs)) { while (list(Sk. $v) = each(Sattnbs))
{ print " <font color=\"#009900\">
$k</font>=\"<font color=\"#990000\">$v</font>\"": } }
print "&gt;": }function endElement(Sparser. Sname) {
print "&lt;/<font color=\"#0000cc\">$name</font>&gt;": }
function characterData(Sparser. $data)
{ print "<b>Sdata</b>"; }
function PIHandler($parser. Starget. $data)
{ switch (strtolower(Starget)) { case "php":
global $parser_file.
// Проверим допустимо ли выпрямить код PHP из документа
// или ограничиться его простым отображением
if (trustedFile($parser_file[Sparser]))
eval($data). else pnntfC'Kofl PHP: <i>fc</i>".
htmlspecialchars(Sdata)): break; } }
function defaultHandler($parser, Sdata) {
if (substrtSdata, 0. 1) == "&" && substr(Sdata. -1. 1)
== ".") { pnntf ('<font color="#aaOOaa">Us</font>'.
html sped a lchars (Sdata)): } else {
printf('<font size="-l">£s</font>'.
htmlspecialchars(Sdata)); } }
function externalEntityRefHandler
(Sparser, SopenEntityNames.
$base. Ssystemld. Spublicld) { if (Ssystemld) {
if (!list($parser. Sfp) = new_xml_parser(Ssystemld)) {
printf("Необрабатываемая секция %s в позиции
Zs\n". SopenEntityNames. Ssystemld);
return FALSE; } while (Sdata = fread($fp. 4096)) {
if (!xml_parse(Sparser. Sdata. feof(Sfp))) {
pnntfC'XML error: Is в стороке %d '%s'
\n". xml_error_string(xml_get_error_code($parser))
. xml_get_currentline_number($parser).
$openEntityNames): xml_parser_free($parser);
return FALSE: } }
xml_parser_free(Sparser). return TRUE; }
return FALSE: }
function new_xml_parser($file)
{ global $parser_file:
$xml_parser = xml_parser_create():
xml_parser_set_option
($xml_parser. XML_OPTION_CASE_FOLDING. 1):
xml_set_element_handler
($xml_parser. "startElement". "endElement"):
xml_set_character_datajiandler
($xml_parser. "characterOata");
xml_set_processing_instruction_handler($xml_parser.
"PIHandler"): xml_set_default_handler
($xml_parser. "defaultHandler"):
xml_set_external_entity_ref_handler
($xml_parser, "externalEntityRefHandler"):
if (!($fp = @fopen($file. "r"))) { return FALSE. }
if (!is_array($parser_file)) { settype($parser_file, "array"); }
Sparser_file[$xml_parser] =
$file. return array($xml_parser. $fp);}
//----------------------.......
if (!(list($xml_parser. $fp) =
new_xml_parser($file))) { dieC'could not open XML input"); }
print "<pre>"; while (Sdata = freadUfp. 4096)) {
if (!xml_parse($xml_parser. Sdata. feof($fp)))
{ die(spnntf("XML error ^s at line *d\n". xml_error_string
(xml_get_error_code
($xml_parser)). xml_get_current_line_number($xml_parser)));} }
print "</pre>": print "parse completed";
xml_parser_free($xml_parser):

Содержимое файла xmltest.xml:

<?xml version='1.0">>
<!DOCTYPE chapter SYSTEM "/just/a/test.dtd" [
<!ENTITY plainEntity "FOO entity">
<!ENTITY systemEntity SYSTEM "xmltest2.xml"> ]>
<chapter> <TITLE>Title &plainEntity:</TITLE> <para>
<informaltable> <tgroup cols="3">
<tbody> <row><entry>al</entry>
<entry morerows="l">bl</entry>
<entry>cl</entry></row> <row><entry>a2</entry>
<entry>c2</entry></row> <row><entry>a3</entry>
<entry>b3</entryxentry>c3</entry></row> </tbody>
</tgroup> </informaltable> </para> SsystemEntity.
<sectl id="about">
<title>About this Document</title> <para>
<!-- this is a comment -->
<?php print 'Hi! PHP version ' .phpverslon(): ?>
</para> </sectl> </chapter>

Подключаемый файл xmltest2.xml:

<?xml version="1.0"?> <!DOCTYPE foo [
<!ENTITY testEnt "test entity"> ]> <foo>
<element attnb="value"/> StestEnt;
<?php print "This is PHP code."; ?> </foo>

xml_parser_create

Инициализация интерпретатора XML

int xml_parser_create ([string encoding])

Необязательным аргументом можно указать кодировку, котор дует использовать: ISO-8859-1 (по умолчанию), US-ASCII, U

Возвращает дескриптор созданного интерпретатора (исполы последующими функциями) или FALSE — при ошибке.

xml_set_object

Разрешение использования интерпретатора XML внутри объекта

void xml_set_object (int parser, object Subject)

Функция позволяет использовать в качестве всех функций oi чиков методы объекта object.

<?php class xml { var Sparser.
function xml (){ // конструктор
$this->parser - xml_j>arser_create();
xml_set_object($this->parser.&$thi s):
xml_set_element_handler
($this->parser."tag_open"."tag_close"):
xml_set_character_data_handler($this->parser."cdata"); }
function parse($data) ( xml parse(5this->parser.$data). }
function tag_oper,(Sparser.Stag.tattnbutes) {
echo "** Tag open: ": var dump($tag.$attributes). }
function cdata($parser.$cdata) {
echo " ++ Data: ": varjJump($cdita): }
function tag_close(Sparser.$tag) {
echo "** Tag close: "; var_dump($tag): }
} // end of class xml $xml_parser = new xml():
$xml_parser-parse('<A ID="99">PHP
<z a= "d"/>aaa</A>')?> < /FONT>

При запуске пример выведет:

** Tag open: stnng(l) "A" array(l) { f"IO"]=> stnng(2) "99"}
++ Data stnng(4) "PHP "
** Tag open: stnng(l) "Z" array(l) { ["A">>
stnng(l) "d" } ** Tag close: stnng(l) "Z"
t-+ Data: stnng(3) "aaa" ** Tag close: stnng(l) "A"

xml_set element_handler

Назначение обработчиков открывающего и закрывающего тега

int xml_set_element_hand1er (int parser, string startElementHandler, string endElementHandler)

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

Функции должны принимать следующие аргументы:

  • startElementHandler (Int parser, string name, array attribs)
  • endElementHandler (int parser, string name)

Аргумент name содержит имя тега, attribs — ассоциативный массив, содержащий атрибуты тега (если они имеются).

xml_set_character_data_handler

Назначение обработчика данных

int xml_set_character_data_handler (int parser, string handler)

Устанавливает пользовательскую функцию с именем handler как обработчик данных документа. Данными считается все то, что находится между тегами, включая пробелы. Эта функция будет вызываться во время интерпретации (при вызове xml_parse()). Она должна соответствовать прототипу:

handler (int parser, string data).

В аргументе data функция получает текущий блок данных.

xml_set_processing_instruction_handler

Назначение обработчика инструкций обработки

int xml_set_processing_instruction_handler (int parser, string handler)

Инструкции обработки имеют следующий формат:

<?target data . ?>

Используя этот формат, можно вставлять в XML документы РНР-кода, но последовательность, обозначающая конечный тег (?>), не должна встречаться в середине кода, иначе оставшаяся часть кода будет рассматриваться интерпретатором как обычные данные. Функция, устанавливаемая в качестве обработчика, должна соответствовать следующему прототипу:

handler (int parser, string target, string data)

В аргументе target функция получает маркер, определяющий тип кода (это может быть не только «php», но и другой, кроме зарезервированного типа «xml»). В аргументе data передается текст всего кода, который содержится внутри тега.

xml_set_default_handler

Установка обработчика по умолчанию

int xml_set_default_handler (int parser, string handler)

Устанавливаемым обработчиком будут обрабатываться все данные, которые не могут быть обработаны иным зарегистрированным обработчиком. Функция обработчика должна соответствовать следующему прототипу:

handler (int parser, string data).

В аргументе data функция получает блок данных для обработки.

xml_set_unparsed_entity_decl_handler

Установка обработчика необрабатываемых данных

int xml_set_unparsed_entity_decl_handler (int parser, string handler)

Данные такого типа (NDATA) определяются спецификацией XML 1.0 (раздел 4.2.2) и имеют подобный следующему формат:

<!ENTITY name {publicld | systemld} NDATA notationName>

Функция обработчика должна соответствовать следующему прототипу:

handler (int parser, string entityNarae, string base, string systemld, string publicld, string notationName).

В аргументе entityName функция получает тип тега, в base в настоящее время всегда содержится пустая строка. В аргументах systemld и publicld содержатся соответственно системный и публичный внешние идентификаторы. Аргумент notationName содержит имя нотации (см. функцию xml_set_notation_decl_handler()).

xml_set notation decl_handler

Установка обработчика объявлений нотаций

int xml_set_notation_decl_handler (int parser, string handler)

Нотации (являющиеся частью документов DTD) описаны в спецификации XML 1.0 (раздел 4.7) и имеют следующий формат:

<!NOTATION na'ie [systemlcl \ publ,cld}>

Функция обработчика должна соответствовать следующему прототипу:

handler (int parser, string notationName, string base, string systemld, string publicld)

В аргументе notationName функция получает имя нотации, в base в настоящее время всегда содержится пустая строка. В аргументах systemld и publicld содержатся соответственно системный и публичный внешние идентификаторы.

xml_set_external_entity_ref_handler

Установка обработчика внешних ссылок

int xml_set_external_entity_ref_handler (int parser, string handler)

Функция обработчика нотаций, содержащих внешние ссылки, должна возвращать целочисленное значение и соответствовать следующему прототипу:

int handler (int parser, string openEntityNames, string base, string systemld, string publicld).

Если обработчик возвращает значение FALSE (или не возвращает никакого), интерпретатор XML прекращает интерпретацию и функция xml_get_error_code() возвращает значение XML_ERROR_EXTERNAL_ENTITY_ HANDLING.

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

xml_parse

Начало интерпретации документа XML

int xml_parse (int parser, string data [, int isFinal])

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

До начала интерпретации следует инициализировать интерпретатор parser и установить все функции-обработчики, которые будет вызывать данная функция. Функция возвращает значение TRUE, если интерпретация блока документа прошла успешно. В случае ошибки возвращается значение FALSE, и затем может быть получена информация об ошибке с помощью функций xml_get_error_code(), xml_error_string(), xml _get_current_line_number (), xml _get_current_col umnjiumber (), xml _get_ current_ byte_index().

xml_get_error_code

Получение кода ошибки интерпретатора XML

int xml_get_error_code (int parser)

Перечисление возвращаемых кодов ошибок (констант) см. в начале главы.

xml_error_string

Получение описания ошибки по ее коду

string xml_error_string (int code)

Функция позволяет получить в строке описание кода ошибки (возвращаемое функцией xml_get_error_code()). Если код недействителен, возвращается FALSE.

xml_get_current_line_number

Получение номера текущей интерпретируемой строки документа

int xml_get_current_line_number (int parser)

xml_get_current_column_number

Получение номера обрабатываемого байта в текущей интерпретируемой строке документа

int xml_get_current_column_number (int parser)

xml_get_current_byte_index

Получение позиции текущего байта документа

int xml_get_current_byte_index (int parser)

Нумерация байтов начинается с 0.

xml_parse_into_struct

Занесение документа XML в структурированный массив

int xml_parse_into_struct (int parser, string data, array &values, array &index)

Функция заносит XML-документ в 2 параллельные структуры: массив values содержит структуру тегов и их содержимое, a Index содержит вспомогательные индексы для облегчения нахождения начальных и конечных тегов в первом массиве (массивы следует передавать по ссылке).

$simple = "<para><note>simple note</note>
</para>"; $р = xml_parser_create();
xml_parse_i nto_struct($p.Ssimple.&$vais.&$т ndex);
xml_parser_free($p). echo "Index "; pnnt_r($index),
echo "\nVals ": pnnt_r($vals);

При запуске сценарий выводит:

Index Arrayf [PARA] » Array ( [0] => 0 [1] => 2 )
[NOTE] => Array ( [0] => 1 ) ) Vals Array(
[0] => Array ([tag] => PARA
[type] => open [level] => 1 ) [1] -> Array ([tag] => NOTE
[type] => complete [level] => 2 [value] => simple note )
[2] => Array ([tag] => PARA k [type] => close
[level] => 1 ; } < /FONT >

Интерпретация сложных документов становится громоздкой при использовании обработчиков. Хотя эта функция и не создает объект, подобный DOM, она генерирует структуру, которую легко преобразовать в древовидную. Можно, например, создавать объекты, представляющие данные. Следующий пример демонстрирует создание объектов из xml базы данных химических элементов.

Файл, moldb.xml

<?xml version="1.0"7> <moldb>
<molecule> <name>Al am ne</name>
<symbol>ala</symbol> <code>A</code>
<type>hydrophobic</type> </molecule>
<molecule> <name>Lysine</name>
<symbol>lys</symbol> <code>K</code>
<type>cha rged</type> </molecule> </moldb>

Сценарий parsemoldb.php, интерпретатор файла moldb.xml:

<?php class AminoAcid { // класс аминокислот
var Sname; // aa имя var Ssymbol:
// трехбуквенный символ var Scode:
// однобуквенный код var Stype: // свойства
function AminoAcid ($aa) { foreach ($aa as $k=>$v)
Sthis->$k = $aa[$k]; } }
function readDatabase(Sfllename) {
// read the xml database of arrrinoacids
Sdata = implode("",file(Sfilename));
Sparser = 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(Sparser,Sdata,&$values.&$tags),
xml_parser_free($parser).
// loop through the structures foreach
($tags as $key=>$val) { if ($key == "molecule")
{ $molranges = $val;
for ($i=0. $1 < count($molranges):
$1+=2) { Soffset = $molranges[$i] + 1;
$len = $molranges[$i + 1] - Soffset: $tdb[]
= parseMol(array_slice($values. Soffset. Slen)): }
} else { continue: } } return $tdb: }
function parseMol($mvalues) {
for ($i=0; $1 < count($mvalues); $i++)
$mol[$mvalues[$i]["tag"]] = $mvalues[$i]["value"]:
return new AminoAcid($mol): }
$db = readDatabaseC'moldb.xml"):
echo "** Database of AminoAcid objects: ";
pnnt_r($db): ?>

После запуска сценария переменная $db будет содержать массив AminoAcid объектов и будет выведено:

** Database of AminoAcid objects: Array (
[0] => aminoacid Object (
[name] => Alamne [symbol] => ala [code] =>
A [type] => hydrophobic ) [1] => aminoacid Object
( ~\ [name] => Lysine \ [symbol] => lys
[code] => К [type] = > charged j ) < /FONT >

xml_parser_free

Закрытие интерпретатора XML

string xml_parser_free (int parser)

xml_parser_set_option

Установка параметра XML-интерпретатора

int xml_parser_set_option (int parser, int option, mixed value)

В аргументе option константой задается устанавливаемый параметр, а в value — ее новое значение. Возможные параметры:

  • XML_OPTION_CASE_FOLDING (тип значения параметра -- integer) -управляет преобразованием имен тегов в верхний регистр (по умолчанию — 1);
  • XML_OPTION_TARGET_ENCODIN6 (тип значения параметра - string) -целевая кодировка: «ISO-8859-1», «US-ASCII» или «UTF-8». По умолчанию та же, что и установленная функцией xml_parser_ create().

xml_parser_get_option

Получение параметра интерпретатора XML

mixed xml_parser_get_option (int parser, int option)

См. также: xml_parser_set_option().

utf8_decode

Преобразование строки UTF-8 в ISO-8859-1. string utf8_decode (string data)

См. также: utf8_encode().

utf8_encode

Кодирование строки ISO-8859-1 в UTF-8 string utf8_encode (string data)

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

Кодировка UTF-8

Размер символа в байтах

Число битов символа

Кодировка

1

7

Obbbbbbb

2

И

llObbbbb lObbbbbb

3

16

lllObbbb lObbbbbb lObbbbbb

4

21

llllObbb lObbbbbb lObbbbbb lObbbbbb

Как видно, размер символа может быть от 1 до 4 бант; b представляет один бит данных.



Содержание раздела