W3docs

PHP XML DOM

Узнайте, как использовать расширение PHP DOM для загрузки, создания, изменения, запросов (XPath) и сохранения XML-документов.

Для чего предназначено расширение DOM

Расширение DOM (Document Object Model) представляет XML-документ в виде дерева узлов в памяти. Каждый элемент, атрибут, текстовый фрагмент и комментарий является объектом-узлом, который можно читать, перемещать, добавлять или удалять. Поскольку весь документ загружается в оперативную память, DOM является правильным инструментом, когда нужно изменять XML, создавать документ с нуля или выполнять XPath-запросы, перемещающиеся по дереву.

На этой странице рассматриваются загрузка, создание, изменение, запросы и сохранение XML с помощью DOMDocument. Сравнение с более лёгкими альтернативами:

  • Используйте расширение SimpleXML, когда нужно лишь читать правильно сформированный XML быстро и с минимумом кода.
  • Используйте XML Parser (Expat) для потоковой обработки очень больших файлов, которые не должны полностью загружаться в память.
  • Обращайтесь к DOM (эта страница), когда нужен полный контроль чтения/записи и XPath.

DOM и libxml используют общую систему ошибок; см. PHP libxml для управления ошибками разбора.

Включение расширения

Расширение DOM поставляется с PHP и включено по умолчанию в большинстве сборок (входит в пакет php-xml на Debian/Ubuntu). Вы можете убедиться в его доступности:

<?php
var_dump(extension_loaded('dom')); // bool(true)

Если расширение отсутствует, установите пакет php-xml для вашей платформы или включите extension=dom в php.ini, затем перезапустите веб-сервер.

Загрузка XML-документа

Создайте DOMDocument и загрузите XML из строки с помощью loadXML() или из файла с помощью load(). Заранее включите libxml_use_internal_errors(true), чтобы некорректная разметка не выводила предупреждения — вместо этого вы сами собираете ошибки.

<?php
$xml = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<books>
  <book id="1"><title>PHP for Beginners</title></book>
  <book id="2"><title>Advanced XML</title></book>
</books>
XML;

libxml_use_internal_errors(true);
$doc = new DOMDocument();

if (!$doc->loadXML($xml)) {
    foreach (libxml_get_errors() as $error) {
        echo trim($error->message) . "\n";
    }
    libxml_clear_errors();
    exit;
}

$root = $doc->documentElement;
echo "Root element: {$root->nodeName}\n";

foreach ($root->getElementsByTagName('title') as $title) {
    echo "Title: {$title->nodeValue}\n";
}

Вывод:

Root element: books
Title: PHP for Beginners
Title: Advanced XML

getElementsByTagName() возвращает живой DOMNodeList, по которому можно сразу проходить через foreach — это обычно понятнее, чем обход childNodes, который также включает текстовые узлы с пробелами между элементами.

Создание XML-документа с нуля

Создавайте документ, добавляя узлы к DOMDocument и прикрепляя их к родительскому элементу. Установите formatOutput = true, чтобы получить отформатированный, читаемый вывод из saveXML().

<?php
$doc = new DOMDocument('1.0', 'UTF-8');
$doc->formatOutput = true;

$root = $doc->createElement('books');
$doc->appendChild($root);

$book = $doc->createElement('book');
$book->setAttribute('id', '1');
$root->appendChild($book);

$title = $doc->createElement('title', 'PHP for Beginners');
$book->appendChild($title);

echo $doc->saveXML();

Вывод:

<?xml version="1.0" encoding="UTF-8"?>
<books>
  <book id="1">
    <title>PHP for Beginners</title>
  </book>
</books>

Ключевые методы:

  • createElement($name, $value) — создаёт элемент, опционально с текстовым содержимым.
  • setAttribute($name, $value) — добавляет или перезаписывает атрибут элемента.
  • appendChild($node) — прикрепляет узел как последнего дочернего элемента к родителю.

Важно: передача текста напрямую в createElement('title', $userInput) не экранирует &, < или > надёжно. Для недоверенного текста добавляйте текстовый узел: $el->appendChild($doc->createTextNode($userInput)), который всегда экранирует специальные символы.

Изменение и удаление узлов

Поскольку всё дерево находится в памяти, вы можете изменять текст, обновлять атрибуты и удалять элементы перед сохранением. Удобный способ найти нужный узел — XPath (рассматривается далее), но здесь мы используем его непосредственно:

<?php
$xml = <<<XML
<books>
  <book id="1"><title>PHP for Beginners</title></book>
  <book id="2"><title>Advanced XML</title></book>
</books>
XML;

$doc = new DOMDocument();
$doc->formatOutput = true;
$doc->loadXML($xml);

$xpath = new DOMXPath($doc);

// Rename the first title
$first = $xpath->query('//book[@id="1"]/title')->item(0);
$first->nodeValue = 'PHP Essentials';

// Remove the second book
$second = $xpath->query('//book[@id="2"]')->item(0);
$second->parentNode->removeChild($second);

echo $doc->saveXML();

Вывод:

<?xml version="1.0"?>
<books>
  <book id="1"><title>PHP Essentials</title></book>

</books>

Чтобы удалить узел, нужно вызвать removeChild() на его родителе — именно поэтому $second->parentNode->removeChild($second) является стандартным идиоматическим способом. Присвоение значения nodeValue заменяет текстовое содержимое элемента.

Запросы с помощью XPath

DOMXPath позволяет выбирать узлы с помощью выражений пути вместо ручного обхода дерева — что значительно лаконичнее вложенных циклов.

<?php
$xml = <<<XML
<books>
  <book id="1"><title>PHP for Beginners</title></book>
  <book id="2"><title>Advanced XML</title></book>
</books>
XML;

$doc = new DOMDocument();
$doc->loadXML($xml);

$xpath = new DOMXPath($doc);

// Every <title> anywhere in the document
foreach ($xpath->query('//title') as $node) {
    echo $node->nodeValue . "\n";
}

// The title of the book whose id is "2"
$result = $xpath->query('//book[@id="2"]/title');
echo "Book 2: " . $result->item(0)->nodeValue . "\n";

Вывод:

PHP for Beginners
Advanced XML
Book 2: Advanced XML

Распространённые шаблоны XPath:

ВыражениеВыбирает
//titleВсе элементы <title> на любой глубине
/books/bookДочерние элементы <book> непосредственно под корнем <books>
//book[@id="2"]Элементы <book> с атрибутом id="2"
//book/@idУзлы атрибута id каждого <book>
//book[1]Первый <book> (индексы XPath начинаются с 1)

Сохранение в файл

Сохраните дерево из памяти с помощью save(), который возвращает false при ошибке (например, при недоступном для записи каталоге).

<?php
$doc = new DOMDocument('1.0', 'UTF-8');
$doc->formatOutput = true;

$root = $doc->createElement('config');
$doc->appendChild($root);
$root->appendChild($doc->createElement('debug', 'false'));

if ($doc->save(__DIR__ . '/output.xml')) {
    echo 'Saved successfully.';
} else {
    echo 'Failed to save — check directory permissions.';
}

Используйте saveXML() (без аргументов), когда нужно получить XML в виде строки — это удобно для возврата из API или вывода в ответе.

Итоги

  • DOMDocument загружает весь XML-документ в изменяемое дерево узлов.
  • Используйте loadXML() / load() для чтения, createElement() и appendChild() для построения, removeChild() для удаления.
  • DOMXPath::query() выбирает узлы с помощью лаконичных выражений пути.
  • save() записывает в файл; saveXML() возвращает документ в виде строки.
  • Выбирайте DOM, когда нужно записывать или запрашивать XML; выбирайте SimpleXML для быстрого чтения и XML Parser для потоковой обработки больших файлов.

Практика

Практика
Что можно делать с PHP XML DOM?
Что можно делать с PHP XML DOM?
Was this page helpful?