PHP SimpleXML
SimpleXML — встроенное расширение PHP для работы с XML-документами через удобный объектный интерфейс.
Введение
SimpleXML — встроенное расширение PHP, которое преобразует XML-документ в объект, доступный через обычный синтаксис свойств и массивов. Вместо того чтобы вручную обходить дерево узлов, вы пишете $xml->book->title — имена элементов становятся свойствами, а повторяющиеся элементы — итерируемыми списками.
Это делает SimpleXML самым быстрым способом прочитать файл конфигурации, обработать XML-ответ от API или создать небольшой XML-документ. На этой странице рассматривается загрузка XML, чтение элементов и атрибутов, работа с пространствами имён, запросы с помощью XPath, изменение документов и обработка ошибок синтаксического разбора.
SimpleXML лучше всего подходит для документов, которые без труда помещаются в памяти и имеют известную, достаточно плоскую структуру. Для очень больших файлов или низкоуровневого управления вам могут больше подойти PHP XML DOM или парсер XML на основе Expat.
Загрузка XML-документа
SimpleXMLElement можно создать из одного из трёх источников:
simplexml_load_string()— разбирает XML из строки (удобно для API-ответов).simplexml_load_file()— разбирает XML из файла или URL.new SimpleXMLElement($xml)— конструктор, который по умолчанию принимает строку.
Все три возвращают SimpleXMLElement, представляющий корневой элемент документа, а не обёртку вокруг всего файла. Поэтому если ваш корневой элемент — <library>, возвращённый объект и есть <library>.
<?php
$data = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<library>
<book category="fiction">
<title>The Hobbit</title>
<author>J.R.R. Tolkien</author>
<price>14.99</price>
</book>
<book category="science">
<title>A Brief History of Time</title>
<author>Stephen Hawking</author>
<price>18.50</price>
</book>
</library>
XML;
$library = simplexml_load_string($data);
echo get_class($library); // SimpleXMLElementЧтение элементов и атрибутов
Дочерние элементы доступны как свойства. Когда элемент повторяется (например, <book>), свойство ведёт себя как список, по которому можно обращаться по индексу через [] или перебирать с помощью foreach. Атрибуты читаются через синтаксис доступа к массиву ($element['attr']).
<?php
$library = simplexml_load_string($data); // the XML from above
echo $library->book[0]->title . "\n"; // The Hobbit
echo count($library->book) . "\n"; // 2
foreach ($library->book as $book) {
echo $book->title . " — " . $book['category'] . "\n";
}Вывод:
The Hobbit
2
The Hobbit — fiction
A Brief History of Time — scienceВажно: элемент, полученный таким образом, является объектом
SimpleXMLElement, а не строкой.$book->priceвыводится как текст благодаря методу__toString(), но для арифметических операций или строгих сравнений сначала приведите его к нужному типу:(float) $book->priceили(string) $book['category']. Забытое приведение типов — наиболее распространённая ошибка при работе с SimpleXML.
Запросы с помощью XPath
Для всего, что выходит за рамки простой навигации — фильтрации, поиска в глубине дерева, условной выборки — используйте xpath(). Он выполняет выражение XPath и возвращает массив совпадающих элементов.
<?php
$library = simplexml_load_string($data);
// Titles of books priced over 10
foreach ($library->xpath('//book[price>10]/title') as $title) {
echo $title . "\n";
}
// The Hobbit
// A Brief History of TimeРабота с пространствами имён
Когда документ использует пространства имён XML, обратиться к элементам с префиксами через обычный доступ к свойствам не получится — необходимо вызвать children() (для элементов) или attributes() (для атрибутов) с URI пространства имён, либо зарегистрировать префикс перед выполнением XPath.
<?php
$rss = <<<XML
<rss xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
<item>
<title>Hello</title>
<dc:creator>Jane Doe</dc:creator>
</item>
</channel>
</rss>
XML;
$xml = simplexml_load_string($rss);
$item = $xml->channel->item;
// Access the dc: namespace by URI
$dc = $item->children('http://purl.org/dc/elements/1.1/');
echo $dc->creator . "\n"; // Jane DoeИзменение и создание XML
SimpleXML позволяет изменять существующие узлы, добавлять новые и сериализовать результат. Присвойте значение свойству, чтобы изменить его, вызовите addChild() для добавления элемента, а addAttribute() — для добавления атрибута. Метод asXML() возвращает документ в виде строки или записывает его в файл, если указан путь.
<?php
$book = simplexml_load_string('<book><title>Old Title</title><price>10.00</price></book>');
$book->title = 'New Title'; // change an existing value
$book->price = '12.50';
$book->addChild('author', 'Jane Doe'); // add a new element
$book->addAttribute('id', '42'); // add an attribute
echo $book->asXML();Вывод:
<?xml version="1.0"?>
<book id="42"><title>New Title</title><price>12.50</price><author>Jane Doe</author></book>Передача имени файла — $book->asXML('book.xml') — записывает документ на диск и возвращает true в случае успеха. Полное описание смотрите в asXML().
Обработка ошибок разбора
Если XML некорректен, функции загрузки возвращают false и генерируют предупреждения PHP. Чтобы перехватывать ошибки тихо и изучать их самостоятельно, включите внутреннюю обработку ошибок через libxml_use_internal_errors() и получите их с помощью libxml_get_errors().
<?php
libxml_use_internal_errors(true);
$broken = "<library><book><title>Unclosed</book></library>";
$xml = simplexml_load_string($broken);
if ($xml === false) {
echo "Failed to parse XML:\n";
foreach (libxml_get_errors() as $error) {
echo trim($error->message) . "\n";
}
libxml_clear_errors();
}Вывод:
Failed to parse XML:
Opening and ending tag mismatch: title line 1 and book
Opening and ending tag mismatch: book line 1 and library
Premature end of data in tag library line 1Всегда проверяйте возвращаемое значение перед использованием результата — обращение к false как к объекту вызовет ошибки «attempt to read property on bool» в последующем коде.
Итоги
- Загружайте XML с помощью
simplexml_load_string(),simplexml_load_file()илиnew SimpleXMLElement(); возвращённый объект является корневым элементом. - Читайте дочерние элементы как свойства, а атрибуты — как ключи массива; приводите к
(string),(int)или(float)перед сравнением или вычислениями. - Используйте
xpath()для фильтрации и глубоких запросов, аchildren()/attributes()с URI — для документов с пространствами имён. - Изменяйте данные через присвоение свойств,
addChild()иaddAttribute(), затем сериализуйте с помощьюasXML(). - Защищайтесь от некорректных данных с помощью
libxml_use_internal_errors()иlibxml_get_errors().
Для более глубокого изучения смотрите Получение значений узлов с помощью SimpleXML, Обзор парсера SimpleXML и низкоуровневые функции libxml.