Работа с XML в PHP: базовые подходы и практические примеры

Раздел: PHP XML -> Обработка XML в PHP

Основные методы обработки XML в PHP

Расширение SimpleXML предоставляет самый простой способ чтения и создания XML-документов. Оно подходит для файлов небольшого и среднего размера, когда не требуется полный контроль над документом. После загрузки дерево XML превращается в объект, к которому можно обращаться как к массиву.

Загрузка из файла:

$xml = simplexml_load_file('catalog.xml');
if ($xml === false) {
    foreach (libxml_get_errors() as $error) {
        echo $error->message;
    }
}

Обход элементов и чтение атрибутов:

$xml = simplexml_load_file('books.xml');
foreach ($xml->book as $book) {
    $title = (string)$book->title;
    $author = (string)$book['author'];
    echo "$title - $author\n";
}

Изменение существующего значения:

$xml->book[0]->title = 'Новое название';
$xml->asXML('books.xml');

Поиск с помощью XPath:

$result = $xml->xpath('//book[@category="php"]');
foreach ($result as $book) {
    echo $book->title;
}

Проблема: Некорректный XML приводит к false. Следует проверять результат и вызывать libxml_get_errors(). Ошибка кодировки решается указанием параметра LIBXML_NOWARNING или обработкой кодировки при загрузке.

Как выполнить полный разбор и модификацию XML с помощью DOM?

DOMDocument загружает весь документ в память и позволяет перемещаться по дереву, добавлять и удалять узлы. Это подходит для сложных преобразований.

$dom = new DOMDocument('1.0', 'utf-8');
$dom->load('books.xml');
$book = $dom->getElementsByTagName('book')->item(0);
$newTitle = $dom->createElement('title', 'Новое название');
$book->replaceChild($newTitle, $book->getElementsByTagName('title')->item(0));
$dom->save('books.xml');

Создание нового документа:

$dom = new DOMDocument();
$root = $dom->createElement('root');
$dom->appendChild($root);
$book = $dom->createElement('book');
$book->setAttribute('id', '1');
$root->appendChild($book);
$book->appendChild($dom->createElement('title', 'PHP'));
echo $dom->saveXML();

Типичная ошибка: Забыть создать элемент через createElement перед добавлением. DOM требует больше памяти, чем SimpleXML.

Как организовать потоковое чтение большого XML-файла?

XMLReader читает документ по одному узлу, не загружая весь файл. Это незаменимо для файлов размером сотни мегабайт.

$reader = new XMLReader();
$reader->open('large.xml');
while ($reader->read()) {
    if ($reader->nodeType == XMLReader::ELEMENT && $reader->localName == 'item') {
        $item = simplexml_import_dom($reader->expand());
        echo $item->title . "\n";
    }
}
$reader->close();

Для записи больших файлов применяется XMLWriter:

$writer = new XMLWriter();
$writer->openURI('output.xml');
$writer->startDocument('1.0', 'UTF-8');
$writer->startElement('data');
for ($i = 0; $i < 1000; $i++) {
    $writer->startElement('row');
    $writer->writeAttribute('id', $i);
    $writer->writeElement('value', "Element $i");
    $writer->endElement();
}
$writer->endElement();
$writer->endDocument();
$writer->flush();

Проблема: XMLReader не позволяет редактировать документ. Для внесения изменений в большие файлы нужно перезаписывать документ с помощью XMLWriter.

Как преобразовать XML с помощью XSLT-шаблона?

Расширение XSLTProcessor применяет трансформацию XSL к XML-документу. Результат может быть строкой, файлом или DOM-документом.

$xsl = new DOMDocument();
$xsl->load('transform.xsl');
$xml = new DOMDocument();
$xml->load('data.xml');
$proc = new XSLTProcessor();
$proc->importStylesheet($xsl);
$result = $proc->transformToXML($xml);
echo $result;

Ошибка: Неправильно составленный XSL или отсутствие расширения XSL приводит к исключениям. Следует проверять наличие модуля php_xsl.

Как проверить XML на соответствие DTD или XSD?

Валидация выполняется через DOMDocument::validate или SchemaValidate.

$dom = new DOMDocument();
$dom->load('document.xml');
if ($dom->validate()) {
    echo 'XML соответствует DTD';
} else {
    echo 'Ошибки валидации:';
    foreach ($dom->getErrors() as $error) {
        echo $error->message;
    }
}

Для схемы XSD:

if ($dom->schemaValidate('schema.xsd')) {
    echo 'Валидация прошла успешно';
}

Типичная ошибка: Неправильный путь к схеме или неверные пространства имен. При ошибках валидации выбрасываются предупреждения, которые следует обрабатывать через libxml_use_internal_errors(true).

Дополнительно стоит упомянуть функцию simplexml_import_dom(), которая позволяет комбинировать DOM и SimpleXML.

Расширенные примеры работы с XML в PHP

Пример 1: Парсинг RSS-ленты с помощью SimpleXML

Пример
$rss = simplexml_load_file('http://example.com/rss');
foreach ($rss->channel->item as $item) {
    echo 'Название: ' . $item->title . "\n";
    echo 'Ссылка: ' . $item->link . "\n";
    echo 'Описание: ' . strip_tags($item->description) . "\n\n";
}
Название: Первая новость
Ссылка: http://example.com/news/1
Описание: Текст первой новости.

Пример 2: Создание Atom-ленты с использованием DOM и namespace

Пример
$dom = new DOMDocument('1.0', 'utf-8');
$feed = $dom->createElementNS('http://www.w3.org/2005/Atom', 'feed');
$dom->appendChild($feed);
$title = $dom->createElement('title', 'Пример ленты');
$feed->appendChild($title);
$entry = $dom->createElement('entry');
$entry->appendChild($dom->createElement('title', 'Запись'));
$feed->appendChild($entry);
echo $dom->saveXML();
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Пример ленты</title>
  <entry>
    <title>Запись</title>
  </entry>
</feed>

Пример 3: Обработка огромного XML-файла (например, логов) с XMLReader

Пример
$reader = new XMLReader();
$reader->open('/var/log/big.xml');
$count = 0;
while ($reader->read()) {
    if ($reader->nodeType == XMLReader::ELEMENT && $reader->localName == 'log') {
        $log = simplexml_import_dom($reader->expand());
        if ($log->level == 'error') {
            $count++;
        }
    }
}
echo "Найдено ошибок: $count";
$reader->close();
Найдено ошибок: 1234

Пример 4: Преобразование XML в многомерный массив с помощью SimpleXML

Пример
function xmlToArray(SimpleXMLElement $xml) {
    $result = (array)$xml;
    foreach ($result as $key => $value) {
        if ($value instanceof SimpleXMLElement) {
            $result[$key] = xmlToArray($value);
        }
    }
    return $result;
}
$xml = simplexml_load_string('First');
print_r(xmlToArray($xml));
Array
(
    [item] => Array
        (
            [@attributes] => Array
                (
                    [id] => 1
                )
            [name] => First
        )
)

Пример 5: Применение XSLT для преобразования XML в HTML

Пример
$xsl = new DOMDocument();
$xsl->load('to-html.xsl'); // XSL, преобразующий в таблицу
$xml = new DOMDocument();
$xml->load('data.xml');
$proc = new XSLTProcessor();
$proc->importStylesheet($xsl);
$result = $proc->transformToXML($xml);
echo $result;
<table>
  <tr><td>1</td><td>Первый</td></tr>
  <tr><td>2</td><td>Второй</td></tr>
</table>

XML в PHP - comments

En
Xml php 1 (php)