Очень просто о PHP, от элементарных понятий до ООП. Часть 11 - работа с XML
Это перевод одиннадцатой статьи из обучающего курса по языку программирования PHP. Прочитав данный цикл статей, вы получите возможность легко писать программы на языке PHP. Данная лекция
знакомит нас с работой с XML-данными.
Начинаем:
Если
Если вы не просидели в пещере последние несколько лет, то вы слышали об XML - инструментарии, на режим разметки которого в последнее время переключается всё больше и больше веб-издателей. Вы, может, даже видели XML-документ в действии - с полностью определёнными тегами и разметкой, и возможно, вам стало интересно каким образом этот беспорядок в коде превращается в понятное человеку содержимое.
Ответ такой: непростым.
Хотя PHP включал поддержку двух стандартных методов синтаксического анализа (читай: осмысления) XML (SAX и DOM) начиная с версии 4.0, сложность и присущие этим методам непрозрачность заставляли их отключать, исключая самых преданных XML-разработчиков. Всё изменилось с версии PHP 5.0, который представляет новые расширения XML, названное SimpleXML , которое может всё (я действительно имею это в виду) в обработке XML-документов. Продолжайте читать и вы узнаете - как.
Плохие старые деньки
Для того чтобы понять почему SimpleXML так крут, немного углубимся в историю.
Во времена "до SimpleXML" существовало два способа обработки XML-документов. Во-первых, это SAX (Simple API for XML), обходящий документ XML и вызывающий определённые функции при нахождении парсером определённых тегов. Например, вы могли бы вызвать одну функцию для обработки начального тега, другую функцию для обработки завершающего тег, а третью функцию - для обработки данных между ними. Во-вторых, это DOM (Document Object Model), предусматривающий создание дерева представления документа XML
в памяти, а затем с помощью перемещение по нему методами обхода дерева. Как только был достигнут определенный узел дерева, мы могли получить и использовать соответствующее содержиние.
Ни один из этих методов не был особенно удобен: SAX требовал от разработчика создания обработчиков событий для каждого типа элементов, встречающихся в файле XML, в то время как при подходе DOM использовался обьектно-ориентированный обход, заставляло разработчика окунаться в среду интенсивно работающей с памятью системы - а следовательно, неэффективной для больших XML-документов. В более широком контексте, в PHP 4.0 использовали множество различных бекэнд-библиотек для каждого из различных расширений XML,
что приводило к непоследовательности в действиях с различными расширениями XML и тем самым создавало проблемы совместимости (а также изрядной путанице для разработчиков).
В PHP 5.0 были предприняты согласованные усилия чтобы решить эту проблему, путём принятия библиотеки libxml2 (http://www.xmlsoft.org/) в качестве стандартной библиотекой для всех расширений XML и указания различным расширениям XML действовать более последовательно. Самое большое изменение в PHP 5 касательно пантеона XML, однако, является расширение SimpleXML, разработаннное Стерлингом Хьюзом, Бобом Ричардсом и Маркусом Боргером,
которое пытается сделать разбор XML-документов значительно более удобным, чем это было в PHP 4.
SimpleXML работает путем преобразования XML-документа в объект, а затем превращения элементов в рамках этого документа в свойства обьектов, к которым можно получить доступ, используя стандартную нотацию обьектов. Это делает SimpleXML легким в перемещении к элементу на любом уровне иерархии XML для доступа к его содержимому. Повторяющиеся элементы на том же уровне дерева документа представлены в виде массива, в то время как коллекции пользовательских элементов могут быть созданы с использованием путей XPath
(о них позднее); эти коллекции затем могут быть обработаны с использованием стандартных конструкций циклов РНР. Доступ к атрибутам элемента так же прост, как доступ к ключам ассоциативного массива - нет ничего нового, для изучения, нет специального кода.
Для того чтобы использовать PHP SimpleXML, ваша сборка PHP должна включать в себя поддержку SimpleXML. Эта поддержка включена по умолчанию как в UNIX-, так и в Windows-версиях PHP 5. Подробнее об этом читайте на http://www.php.net/manual/en/ref.simplexml.php. Если вы являетесь пользователем PHP 4, то вам не повезло - SimpleXML доступна только для PHP 5.
Маленькая зверюшка
Чтобы понять как работает SimpleXML, рассмотрим следующий файл XML:
Теперь нам надо добраться до содержимого элементов <name>, <age>, <species> и <parents>. С SimpleXML это просто:
<?php
// установим имя xml-файла
$file = "pet.xml";
// загрузим файл
$xml = simplexml_load_file($file) or die ("Не могу загрузить файл XML!");
// доступ к данным XML
echo "Имя: " . $xml->name . "\n";
echo "Возраст: " . $xml->age . "\n";
echo "Любимая еда: " . $xml->species . "\n";
echo "Родители: " . $xml->parents->mother . " и " . $xml->parents->father . "\n";
?>
Действия начинаются с функции simplexml_load_file(), которая принимает путь и имя xml-файла, который будем разбирать. Результатом разбора станет обьект PHP, все свойства которого соответствуют элементам корневого элемента. Данные элемента можно получить стандартной нотацией обьект->свойство, начинающейся с корневого элемента и движущейся вниз по иерархическому пути в документе.
Подобно тому, как вы читаете данные, так-же можно из и записывать. SimpleXML позволяет легко изменять содержимое конкретного элемента XML - просто присвойте новое значение соответствующему свойству объекта. Вот пример:
<?php
// установим имя файла
$file = "pet.xml";
// загрузим файл
$xml = simplexml_load_file($file) or die ("Не могу загрузить файл XML!");
// изменим данные XML
$xml->name = "Вася Капустин";
$xml->age = 4;
$xml->species = "капуста";
$xml->parents->mother = "Мариванна Капустина";
$xml->parents->father = "Сансаныч Капустин";
// запишем данные в файл
file_put_contents($file, $xml->asXML());
?>
Здесь вначале читается оригинальный xml-файл, затем данные персонажа, находящиеся в каждом элементе, изменяются установки нового значения соответствующему свойству обьекта. Метод asXML() обычно используется для сохранения дерева XML в стандартное устройство вывода, в данном случае в сочетании с функцией file_put_contents() он использован для перезаписи файла-источника xml-файлом с новыми данными.
Город грехов
Повторяющиеся элементы на том же уровне иерархии XML представлены в виде массива элементов, и могут быть получены с помощью числовых индексов. Чтобы увидеть, как это работает, рассмотрим следующий файл XML:
Вот PHP-скрипт, который читает файл и выводит данные:
<?php
// установим имя файла XML
$file = "sins.xml";
// загрузим файл
$xml = simplexml_load_file($file) or die ("Не могу загрузить файл XML!");
// доступ к каждому элементу <sin>
echo $xml->sin[0] . "\n";
echo $xml->sin[1] . "\n";
echo $xml->sin[2] . "\n";
echo $xml->sin[3] . "\n";
echo $xml->sin[4] . "\n";
echo $xml->sin[5] . "\n";
echo $xml->sin[6] . "\n";
?>
Если хотите, можете написать цикл перебора коллекции foreach(), как в следующем листинге:
<?php
// установим имя файла XML
$file = "sins.xml";
// загрузим файл
$xml = simplexml_load_file($file) or die ("Не могу загрузить файл XML!");
// проходим по коллекции элементов <sin> foreach ($xml->sin as $sin) { echo "$sin\n"; }
?>
Начинают вырисовываться формы...
SimpleXML обрабатывает атрибуты элементов так-же прозрачно, как и сами элементы с их содержимым. Пары артибут-значение представляются как члены ассоциативного массива PHP, и могут быть доступны как обычные элементы массива. Чтобы понять как это работает, рассмотрим такой скрипт:
<?php
// создадим строку XML
$str = <<< XML
<?xml version="1.0"?>
<shapes>
<shape type="circle" radius="2" />
<shape type="rectangle" length="5" width="2" />
<shape type="square" length="7" />
</shapes>
XML;
// загрузим строку
$xml = simplexml_load_string($str) or die ("Не могу загрузить строку XML!");
// для каждой фигуры
// вычислим площадь
foreach ($xml->shape as $shape) {
if ($shape['type'] == "circle") {
$area = pi() * $shape['radius'] * $shape['radius'];
}
elseif ($shape['type'] == "rectangle") {
$area = $shape['length'] * $shape['width'];
}
elseif ($shape['type'] == "square") {
$area = $shape['length'] * $shape['length'];
}
echo $area."\n";
}
?>
В отличие от предыдущих примеров, которые использовали внешний файлы XML, этот создаёт XML динамически и загружает его в SimpleXML методом simplexml_load_string().Затем XML разбирается циклом foreach(), и для каждой фигуры вычисляется её площадь, основываясь на типе атрибута <shape> каждого элемента. Листинг выше показывает, что можно получить значения атрибутов как ключи ассоциативного массива для каждого свойства элемента.
Мишень помечена крестиком
SimpleXML также поддерживает пользовательские коллекции элементов через пути XPath. Для новичков в XML, XPath - это стандартный механизм адресации документа XML, позволяющий разработчикам получить доступ к коллекциям элементов, атрибутов или текстовых узлов в документе. Узнайте больше об XPath на страницах http://www.w3.org/TR/xpath.html и http://www.melonfire.com/community/columns/trog/article.php?id=83.
Теперь, давайте предположим, что нам надо напечатать все элементы <desc>. Вы можете пройти по массиву элементов <item>, как описывалось ранее... или вместо этого вы можете просто создать собственную коллекцию элементов <desc> методом xpath(), и пройтись по ним:
<?php
// установим имя файла XML
$file = "ingredients.xml";
// загрузщим файл
$xml = simplexml_load_file($file) or die ("Не могу загрузить файл XML!");
// извлечём все элементы <desc> и напечатаем
foreach ($xml->xpath('//desc') as $desc) {
echo "$desc\n";
}
?>
Используя XPath, вы можете получить даже больше - например, создать коллекцию <desc> только из тех элементов, величина которых равна 2 или более.
<?php
// установим имя файла XML
$file = "ingredients.xml";
// загрузим файл
$xml = simplexml_load_file($file) or die ("Не могу загрузить файл XML!");
// получим все элементы и напечатаем их
foreach ($xml->xpath('//item[quantity > 1]/desc') as $desc) {
echo "$desc\n";
}
?>
Без XPath сделать это будет гораздо сложнее пяти строк кода... попробуйте сами и увидите!
Вечер в Мулен Руж
Мы увидели что может XPath, так давайте-же посмотрим, как его можно реально использовать. Предположим, у вас есть множество описаний фильмов, размеченных в XML, вот так:
<?xml version="1.0"?>
<review id="57" category="2">
<title>Мулен Руж</title>
<teaser>
Видение режиссера База Лурмана города Парижа на рубеже веков.
Остроумное, сексуальное... и совершенно незабываемое
</teaser>
<cast>
<person>Николь Кидман</person>
<person>Эван МакГрегор</person>
<person>Джон Легузьямо</person>
<person>Джим Бродбент</person>
<person>Ричард Роксбург</person>
</cast>
<director>Баз Лурман</director>
<duration>120</duration>
<genre>Романтическая комедия</genre>
<year>2001</year>
<body>
Стильная впечатляющая феерия. Мулен Руж трудно
классифицировать, но это и история любви и костюмированная драма,
и музыкальный фильм, и комедия. Режиссёр Лурман (хорошо известный
постановке Уильяма Шекспира "Ромео и Джульетта") поставил простые
темы - любви, ревности и одержимости - и сделали нечто совершенно
новое и отличное путем постановки их на музыку.
</body>
<rating>5</rating>
</review>
Теперь вы хотите показать обзор на своём веб-сайте. Итак, вам требуется PHP-скрипт для извлечения данных из этого файла в требуемом месте HTML-шаблона. Со всем что вы изучили это легко, что и показывает код ниже:
<?php
// установим имя файла XML
// обычно эти данные берутся из запроса,
// но мы упростим
$file = "57.xml";
// загрузим файл
$xml = simplexml_load_file($file) or die ("Не могу загрузить файл XML!");
?>
<html>
<head><basefont face="Arial"></head>
<body>
<!-- название и год -->
<h1><?php echo $xml->title; ?> (<?php echo $xml->year; ?>)</h1>
<!-- тизер -->
<h3><?php echo $xml->teaser; ?></h3>
<!-- тело обзора -->
<?php echo $xml->body; ?>
<!-- режиссёр, актёры, длительность и рейтинг -->
<p align="right"/>
<font size="-2">
Режиссёр: <b><?php echo $xml->director; ?></b>
<br />
Длительность: <b><?php echo $xml->duration; ?> min</b>
<br />
Актёрский состав: <b><?php foreach ($xml->cast->person as $person) { echo "$person "; } ?></b>
<br />
Рейтинг: <b><?php echo $xml->rating; ?></b>
</font>
</body>
</html>
Довольно просто, ага?
Вот и все на данный момент. В двенадцатой части PHP 101, я расскажу вам о новой модели обработки исключений в PHP 5, показывая, как вы можете использовать его чтобы контролировать ваш сценарий, прежде чем они аварийно завершится и всё испортит. Увидимся там!