Обработка XML документов в PHP

Раздел: Разработка на 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 автоматически форматирует отступы.

работа с XML в PHP - comments

En
Php xml (php)