»спользование XML в PHP

ƒоставка цветов в »збербаш —лужба доставки среди цветов.

Ёта стать€, как ¬ы уже скорее всего пон€ли из названи€, посв€щена тому, как можно использовать XML дл€ хранени€ данных, которые будут использоватьс€ из скриптов, написанных на PHP. Ѕедем считать, что ¬ы уже знаете, что такое XML и с чем его ед€т. ѕримеры к статье ¬ы можете скачать отсюда. Ќаш план такой. —начала мы узнаем, какие функции есть дл€ работы с XML в PHP и как ими пользоватьс€. „тобы это лучше пон€ть, мы рассмотрим небольшой скрипт, который будет отображать структуру нашего XML-документа.

ѕриступим. Ќе хочу € нудно и долго рассказывать общие слова про то, как работать с XML в PHP, лучше давайте разберем это все на примере. »так, постановка задачи: написать скрипт, который будет показывать структуру XML-документа. ¬ примерах это файл xml.php.
—начала создадим XML-документ (в примерах это test.xml). ѕусть в этом файле будут описыватьс€ фотографии. ќсобо мудрить мы не будем, и обойдемс€ без описани€ DTD (не путать с DDT :)). «десь по€вл€етс€ перва€ непри€тна€ особенность PHP: XML-документы, которые должны обрабатыватьс€ из скрипта могут буть написаны в следующих кодировках: US-ASCII, ISO-8859-1 и UTF-8. “.к. нам нужно описывать фотографии по-русски, то придетс€ выбрать последнюю кодировку, т.к. в первых друх нет русских букв. Ќе все текстовые редакторы могут работать с этой кодировкой. я, например, набирал XML в редакторе SciTE. ќн маленький, бесплатный и у него хороша€ подсветка синтаксиса (в том числе PHP и XML). Ќаш XML-документ будет выгл€деть так:
<?xml version="1.0" encoding="UTF-8"?>
<album>
<foto smallfoto="Fotos/1smallvelo.jpg " bigfoto="Fotos/1bigvelo.jpg ">
<title>Ќазвание 1</title>
<comment>ƒлинный комментарий
на несколько строк 1</comment>
<date>26.05.2003</date>
<color/>
<detailed>0</detailed>
</foto>
<foto smallfoto="Fotos/smallbardak.jpg " bigfoto="Fotos/bigbardak.jpg ">
<title>Ќазвание 2</title>
<comment> ƒлинный комментарий
на несколько строк 2</comment>
<date>27.05.2003</date>
<color/>
<detailed>1</detailed>
</foto>
</album>
"‘изический" смысл тегов в XML сейчас значени€ не имеет (хот€ там вроде и так все пон€тно). ≈динственное, что только <color/> здесь может обозначать цветна€ фотка или нет. Ёто здесь только дл€ примера тега, у которого нет закрывающегос€.
ј теперь напишем скрипт, который показывал бы структуру XML-документа. ƒл€ работы с XML в PHP есть больше 20 функций. –ассмотрим дл€ начала самые необходимые. ¬от этот скрипт:
<?
$xmlfilename = "test.xml";
$code = "UTF-8"; //  одировка xml-а
$curcode = "Windows-1251"; // “екуща€ кодировка

$level = 0; // ”ровень вложенности
$list = array(); // —писок элементов в xml-файле

// ѕреобразует строку из Unicode
function encoding ($str)
{
global $code;
global $curcode;

$str = mb_convert_encoding($str, $curcode, $code);
return $str;
}

function drawspace()
{
global $level;
for ($i = 0; $i < $level * 10; $i++)
{
echo " ";
}
}

// ќбрабатывает текст между тегами
function characterhandler ($parser, $data)
{
global $code;
global $curcode;

drawspace();
$data = encoding($data, $curcode, $code);
$data = trim($data)."<br>";
echo $data;
}

// ќбрабатывает открывающиес€ теги
function starthandler ($parser, $name, $attribs)
{
global $level;
global $list;

global $code;
global $curcode;

$name = encoding($name, $curcode, $code);
$list[] = $name;
drawspace();
echo "<<font color='blue' size='+1'>$name</font>";
foreach ($attribs as $atname => $val)
{
echo encoding("$atname => $val");
}
echo "><br>";
$level++;
}

// ќбрабатывает закрывающиес€ теги
function endhandler ($parser, $name)
{
global $level;
global $list;
array_pop($list);
$level--;
drawspace();
echo "<<font color='blue' size='+1'>/$name</font>><p>";
}

// —оздадим парсер
$parser = xml_parser_create($code);
if (!$parser)
{
exit ("Ќе могу создать парсер");
}
else
{
echo "ѕарсер успешно создан<p>";
}

// ”становим обработчики тегов и текста между ними
xml_set_element_handler($parser, 'starthandler', 'endhandler');
xml_set_character_data_handler($parser, 'characterhandler');

// ќткроем файл с xml
$fp = fopen ($xmlfilename, "r");
if (!$fp)
{
xml_parser_free($parser);
exit("Ќе могу открыть файл");
}

while ($data = fread($fp, 4096))
{
if (!xml_parse($parser, $data, feof($fp)))
{
die(sprintf("ќшибочка вышла: %s в строке %d",
xml_error_string(xml_get_error_code($parser)),
xml_get_current_line_number($parser)));
}
}

fclose ($fp);
xml_parser_free($parser);
?>
ѕосле объ€влений вспомогательных функций, необходимо в первую очередь создать парсер. Ёто можно сделать одной из функциий xml_parser_create или xml_parser_create_ns. ѕерва€ имеет один необ€зательный параметр, который обозначает кодировку, в которой написан XML-документ. ≈сли его не указать, то по-умолчанию считаетс€, что он написан как ISO-8859-1. Ќо, как € писал выше, это нам не подходит и мы выбирает UTF-8. “.к. обозначение этой кодировки нам еще понадобитс€, то вынесем ее в глобальную переменную ($code = "UTF-8";). “акже вынесем туда кодировку, в которой будет выводитьс€ текст в браузер ($curcode = "Windows-1251";). ‘ункци€ xml_parser_create_ns имеет дополнительный (тоже необ€зательный) параметр, который обозначает символ, которым в документе будут раздел€тьс€ пространства имен. “.к. нам сейчас это не надо, то мы воспользовались первой функцией. ≈сли парсер создан успешно, то паременна€ $parser получит значение, отличное от нул€.
ѕосле этого надо указать парсеру XML, какие функции вызывать при по€влении в тексте тегов XML. ¬ нашем примере это сделано так:
// ”становим обработчики тегов и текста между ними
xml_set_element_handler($parser, 'starthandler', 'endhandler');
xml_set_character_data_handler($parser, 'characterhandler');
‘ункци€ xml_set_element_handler устанавливает обработчики дл€ открывающихс€ и закрывающихс€ тегов. ¬ качестве первого параметра им передаетс€ парсер, который мы создали до этого. ј в качестве второго и третьего - имена функций, которые будут вызыватьс€ по мере того, как будут попадатьс€ открывающиес€ и закрывающиес€ тего соответственно. Ёти функции должны быть определены определенным образом. ‘ункци€ дл€ открывающихс€ тегов должна выгл€деть примерно так:
// ќбрабатывает открывающиес€ теги
function starthandler ($parser, $name, $attribs)
{
}
ѕри ее вызове ей передаютс€ парсер, который мы создали, им€ обрабатываемого тега и его атрибуты (то, что находитс€ в угловых скобках после имени). ≈сли с именем никаких особенностей нет, то атрибуты передаютс€ как ассоциативный массив, т.е. в виде ключ => значение. ѕоэтому мы их и обрабатываем следующим образом:

foreach ($attribs as $atname => $val)
{
echo encoding("$atname => $val");
}
¬се тоже самое и дл€ закрывающихс€ тегов, только функции не передаютс€ атрибуты, которых в принципе быть не может у закрывающегос€ тега:
function endhandler ($parser, $name)
{
}
“ут есть одна интересна€ деталь. ƒаже если у тега нет закрывающегос€, то втора€ функци€ все-равно вызываетс€. ≈сли ¬ы посмотрите на работу скрипта, то увидите, что дл€ тега <color/> у нас получилось:
<COLOR>
</COLOR>
ј чтобы обрабатывать текст, который располагаетс€ между тегами, надо установить соответствующий обработчик функцией xml_set_character_data_handler. ≈й пользоватьс€ точно так же, только ее вторым аргументом должно быть им€ функции, котора€ объ€влена таким образом:
function characterhandler ($parser, $data)
“о есть так же, как и дл€ закрывающегос€ тега. »менно в нее передаютс€ все данные наподобие "Ќазвание 1" или "ƒлинный комментарий на несколько строк 2" из нашего примера. Ќу и, наконец, самое главное - как читать XML-документ. ќказываетс€ просто - как обычный текстовый файл. “.е. открываем его функцией fopen, например так:
$fp = fopen ($xmlfilename, "r");
» читаем из него все строки, которые потом передаем в функцию xml_parse:
while ($data = fread($fp, 4096))
{
if (!xml_parse($parser, $data, feof($fp)))
{
die(sprintf("ќшибочка вышла: %s в строке %d",
xml_error_string(xml_get_error_code($parser)),
xml_get_current_line_number($parser)));
}
}
” xml_parse три аргумента. ѕервый - переменна€ созданного нами раньше парсера, второй - прочитанна€ строка, а третий (необ€зательный) - признак того, что пора заканчивать парсить (вот мы туда и передаем значение того, кончилс€ ли файл). ” нас еще вставлена проверка ошибок. “ам вроде все €сно из названи€. xml_get_error_code возвращает код ошибки, по которому xml_error_string создает строку, котора€ описывает эту ошибку.
ѕосле всего этого надо не забыть уничтожить парсер. Ёто делаетс€ функцией xml_parser_free:
xml_parser_free($parser);
“еперь одна из самых непри€тных особенностей. “.к. мы писали XML как Unicode, то и строки нам передаютс€ в той же кодировке. ј так как обычно сайт стро€т на более привычной кодировке (Koi8, Windows), то с этим Unicod'ом надо что-то делать. » вот здесь начинаетс€ самое непри€тное. ¬ расширении PHP, которое отвечает за XML, есть две функции дл€ перекодировки UTF-8. Ёто функци€ utf8_decode, котора€ преобразует строку из UTF-8, и функци€ utf8_encode, котора€ наоборот преобразует в UTF-8. Ќо они нам не подход€т по той причине, что могут работать с кодировкой ISO-8859-1, в которой нет русских букв.   счастью, разработчики PHP все-таки сделали функции, которые могут буз проблем работать и с другими кодировками - это mb_convert_encoding. ¬ данном случае мы ее использовали так:
$str = mb_convert_encoding($str, $curcode, $code);
$curcode и $code это переменные, в которых хран€тьс€ названи€ кодировок (помните, мы их раньше объ€вили глобальными?). — этой функцией все пон€тно: первый аргумент - это исходна€ строка, второй - название кодировки, в которую преобразуем, а третий аргумент (необ€зательный) - кодировка, из которой преобразуем. ‘ункци€ возвращает нам новую строку.  азалось бы, что все хорошо, есть функци€, она здорово работает (это действительно так), но, чтобы она работала, надо, чтобы было подключено расширение к PHP - mbstring (multi byte string). ƒл€ этого, если вы работаете из Windows, в файле php.ini надо раскомментировать строку extension=php_mbstring.dll. Ќо если дома это сделать несложно, то вот на хостинге, где расположен ¬аш сайт, оно (расширение) может быть не подключено. »менно поэтому € вынес перекодировку в отдельную функцию, чтобы ее можно было легко исправить:
// ѕреобразует строку из Unicode
function encoding ($str)
{
global $code;
global $curcode;

$str = mb_convert_encoding($str, $curcode, $code);
return $str;
}
≈сли у ¬ас есть идеи насчет того, как обойтись без mb_convert_encoding - пишите мне
Ёто были самые простые функции дл€ работы с XML. „тобы было интереснее, в нашем скрипте € считаю уровень вложенности дл€ тегов (это дл€ того, чтобы правильно смещать текст вправо) и еще в глобальную переменную $list занос€тс€ открывающиес€ теги, а при по€влении закрывающегос€ - выбрасываетс€ последний элемент. “.о. в $list хранитс€ путь по которому мы прошли до текущего тега, а сам этот тег находитс€ в конце списка.
“еперь давайте немного побалуемс€ и посмотрим, как работает обработка ошибок. ”берем из тега color слеш. “о есть оставим <color>, как будто мы забыли его закрыть. » вот что нам выдает PHP: "ќшибочка вышла: mismatched tag в строке 16". » на этом обработка прекращаетс€. “акже "mismatched tag" будет, если мы перенесем закрывающийс€ тег <data/> после тега <foto/>.
ѕоиграемс€ с кодировками. ≈сли сохранить наш XML-документ в кодировке Windows-1251 и честно это указать в заголовке <?xml version="1.0" encoding="Windows-1251"?> (не забудьте исправить соответствующую глобальную переменную в скрипте), то PHP... благополучно вылетает :) ѕо крайней мере, так было у мен€. я этот скрипт испытывал на такой конфигурации: Win2000 + SP3; Apache 1.3.27; PHP 4.3.1.
ѕока вроде бы все. ≈сли будут вопросы и замечани€ - пишите мне

јвтор неизвестен



ѕри перепечатке информации делайте, пожалуйста, ссылку на наш сайт (либо поделитьс€ вконтакте, гугл+ или делитесь в одноклассниках статьЄй). —пасибо!

»сточник: www.wr-script.ru©
, 2004-2023г.

ƒелитесь с друзь€ми в соцсет€х. јктивные комментаторы получают свежие скрипты и бесплатные доработки от WR-Script.ru!

¬ернутьс€ к стать€м помощи WEB-мастеру

WR-–°—З—С—В—З–Є–Ї