Обработка XML документов в PHP
Основные подходы к работе с XML в PHP
Какое решение самое эффективное для типичных задач с XML?
Для большинства сценариев, таких как чтение конфигурационных файлов, обработка простых XML-лент и извлечение данных, оптимальным выбором является расширение SimpleXML. Оно позволяет превратить XML-документ в объект, с которым можно работать как с обычными свойствами и массивами. Простота и скорость делают его лучшим вариантом для повседневной работы.
Пример простейшего чтения XML:
$xml = simplexml_load_file('data.xml');
echo $xml->book->title;Этот код выводит заголовок первой книги. Для безопасной обработки ошибок проверяйте результат:
$xml = simplexml_load_file('data.xml');
if ($xml === false) {
// ошибка загрузки
foreach (libxml_get_errors() as $error) {
echo $error->message;
}
libxml_clear_errors();
} else {
echo $xml->book->title;
}Проблемы и ошибки
- Файл отсутствует или поврежден: проверка на
falseобязательна. - Пробелы в именах узлов: используйте
$xml->{'node name'}. - Пространства имен: обращайтесь через
->children('ns', true).
Как выполнить расширенное манипулирование XML документом?
Если требуется не только читать, но и создавать, изменять или удалять узлы, а также использовать XPath, подходит расширение DOMDocument. Оно предоставляет полный контроль над структурой документа и работает в соответствии со стандартом DOM.
Пример создания простого XML:
$dom = new DOMDocument('1.0', 'UTF-8');
$root = $dom->createElement('catalog');
$book = $dom->createElement('book');
$title = $dom->createElement('title', 'PHP Guide');
$book->appendChild($title);
$root->appendChild($book);
$dom->appendChild($root);
echo $dom->saveXML();Частые ошибки при использовании DOMDocument
- Забывают включить форматирование:
$dom->formatOutput = true;для читаемого вывода. - Неправильная обработка кодировки: создавайте документ с явной кодировкой.
Как обработать очень большой XML файл без загрузки в память?
Для потокового чтения, не загружающего весь документ, существует расширение XMLReader. Оно позволяет последовательно обрабатывать узлы, что критично при работе с гигабайтными файлами (например, дампами БД).
Пример чтения книг из большого XML:
$reader = new XMLReader();
$reader->open('huge.xml');
while ($reader->read()) {
if ($reader->name === 'book' && $reader->nodeType == XMLReader::ELEMENT) {
$xml = $reader->readOuterXml();
$simplexml = simplexml_load_string($xml);
echo $simplexml->title . "\n";
}
}
$reader->close();Типичные сложности
- Необходимо явно закрывать ридер:
$reader->close(). - Вложенные элементы: используйте
XMLReader::read()в сочетании сXMLReader::next().
Как создать XML документ с контролем форматирования и пространств имён?
Расширение XMLWriter предоставляет простой интерфейс для последовательного создания XML с автоматическим управлением отступов и пространствами имён.
Пример создания документа с namespace:
$writer = new XMLWriter();
$writer->openMemory();
$writer->startDocument('1.0', 'UTF-8');
$writer->setIndent(4);
$writer->startElementNS('dc', 'metadata', 'http://purl.org/dc/elements/1.1/');
$writer->writeElementNS('dc', 'title', null, 'My Book');
$writer->endElement();
$writer->endDocument();
echo $writer->outputMemory();Ошибки новичков
- Не вызывают
startDocument()иendDocument()- документ будет без XML-заголовка. - Забывают закрыть все открытые элементы:
endElement()должен быть вызван для каждогоstartElement().
Ниже приведены расширенные примеры для каждого рассмотренного подхода.
Пример 1: парсинг RSS-ленты с SimpleXML и XPath
$rss = simplexml_load_file('http://example.com/rss');
$rss->registerXPathNamespace('content', 'http://purl.org/rss/1.0/modules/content/');
$items = $rss->xpath('//item');
foreach ($items as $item) {
$title = (string)$item->title;
$link = (string)$item->link;
$encoded = (string)$item->children('content', true)->encoded;
echo "Заголовок: $title\nСсылка: $link\n";
}Заголовок: Новость 1 Ссылка: http://example.com/news1
Пояснение: Регистрируем пространство имён content, используем XPath для поиска всех item.
Пример 2: создание XML с CDATA и атрибутами через DOMDocument
$dom = new DOMDocument('1.0', 'UTF-8');
$dom->formatOutput = true;
$root = $dom->createElement('article');
$root->setAttribute('id', '123');
$content = $dom->createElement('content');
$cdata = $dom->createCDATASection('<b>HTML внутри</b>');
$content->appendChild($cdata);
$root->appendChild($content);
$dom->appendChild($root);
echo $dom->saveXML();<?xml version="1.0" encoding="UTF-8"?> <article id="123"> <content><![CDATA[<b>HTML внутри</b>]]></content> </article>
Пояснение: С помощью CDATASection можно вставлять неэкранированный HTML, а атрибуты задаются через setAttribute.
Пример 3: потоковое чтение большого XML с фильтрацией
$reader = new XMLReader();
$reader->open('products.xml');
while ($reader->read()) {
if ($reader->name === 'product' && $reader->nodeType == XMLReader::ELEMENT) {
$price = $reader->getAttribute('price');
if ((float)$price > 100) {
$xml = $reader->readOuterXml();
$product = simplexml_load_string($xml);
echo "Товар: {$product->name}, Цена: $price\n";
}
}
}
$reader->close();Товар: Телевизор, Цена: 150
Пояснение: Получаем атрибут 'price', фильтруем по условию, для каждого подходящего товара загружаем фрагмент в SimpleXML для удобного доступа к дочерним элементам.
Пример 4: генерация XML с несколькими namespace через XMLWriter
$writer = new XMLWriter();
$writer->openURI('output.xml');
$writer->startDocument('1.0', 'UTF-8');
$writer->setIndent(2);
$writer->startElementNS('svg', 'svg', 'http://www.w3.org/2000/svg');
$writer->startAttribute('width');
$writer->text('100');
$writer->endAttribute();
$writer->startAttribute('height');
$writer->text('100');
$writer->endAttribute();
$writer->writeComment('Simple SVG circle');
$writer->startElementNS('svg', 'circle', null);
$writer->startAttribute('cx');
$writer->text('50');
$writer->endAttribute();
$writer->startAttribute('cy');
$writer->text('50');
$writer->endAttribute();
$writer->startAttribute('r');
$writer->text('40');
$writer->endAttribute();
$writer->endElement();
$writer->endElement();
$writer->endDocument();
$writer->flush();
echo file_get_contents('output.xml');<?xml version="1.0" encoding="UTF-8"?> <svg:svg xmlns:svg="http://www.w3.org/2000/svg" width="100" height="100"> <!--Simple SVG circle--> <svg:circle cx="50" cy="50" r="40"/> </svg:svg>
Пояснение: Используется startElementNS с префиксом и URI, атрибуты задаются через startAttribute. XMLWriter автоматически форматирует отступы.