XML в PHP от простого чтения до сложных преобразований
Основные подходы к обработке XML в PHP
Как загрузить и разобрать XML-документ с минимальным кодом?
Наиболее эффективное и распространенное решение - расширение SimpleXML. Оно преобразует XML в объект, с которым можно работать как с обычным PHP-объектом. Подходит для большинства задач: чтение конфигураций, обмен данными с API, обработка небольших и средних файлов.
Пример: загрузка XML из строки
$xmlString = '<book><title>PHP для начинающих</title><author>Иван Петров</author></book>';
$xml = simplexml_load_string($xmlString);
echo $xml->title; // PHP для начинающих
Xml файл php (работа с xml в php)
Пример: загрузка из файла
$xml = simplexml_load_file('books.xml');
foreach ($xml->book as $book) {
echo $book->title . ' - ' . $book->author . "\n";
}
Excel файлы php (работа с excel-файлами в php)
Доступ к атрибутам
$xml = simplexml_load_string('<book id="123"><title>PHP</title></book>');
echo $xml['id']; // 123
Изменение и сохранение
$xml->title = 'Новое название';
$xml->addChild('price', 1000);
file_put_contents('books.xml', $xml->asXML());
Проблема: при загрузке некорректного XML SimpleXML генерирует предупреждения (warning) и возвращает false. Решение: проверять результат и подавлять ошибки с помощью libxml_use_internal_errors(true).
libxml_use_internal_errors(true);
$xml = simplexml_load_file('broken.xml');
if ($xml === false) {
foreach (libxml_get_errors() as $error) {
echo $error->message;
}
libxml_clear_errors();
}
Как управлять XML с полным контролем над структурой?
Расширение DOMDocument предоставляет полную реализацию DOM. Подходит для создания сложных документов, вставки узлов в произвольные позиции, работы с пространствами имён и валидацией.
Пример: создание XML с нуля
$dom = new DOMDocument('1.0', 'UTF-8');
$root = $dom->createElement('catalog');
$dom->appendChild($root);
$book = $dom->createElement('book');
$book->setAttribute('id', '1');
$root->appendChild($book);
$title = $dom->createElement('title', 'PHP и MySQL');
$book->appendChild($title);
echo $dom->saveXML();
Проблема: DOMDocument требует явного управления памятью при больших документах, но в целом стабилен. Ошибка: попытка использовать специальные символы в тексте узла - они должны быть экранированы. DOM делает это автоматически при использовании метода createTextNode.
Как обработать очень большой XML-файл без загрузки в память?
Расширение XMLReader позволяет читать документ потоково, узел за узлом. Идеально для файлов размером в гигабайты.
Пример: чтение большого RSS-канала
$reader = new XMLReader();
$reader->open('big.xml');
while ($reader->read()) {
if ($reader->nodeType == XMLREADER::ELEMENT && $reader->localName == 'item') {
$item = $reader->readOuterXml();
// обработка одного элемента
}
}
$reader->close();
Как создать большой XML-файл, не храня весь документ в памяти?
XMLWriter пишет XML потоково. Полезно при экспорте больших наборов данных.
Пример: потоковая запись
$writer = new XMLWriter();
$writer->openURI('output.xml');
$writer->startDocument('1.0', 'UTF-8');
$writer->startElement('catalog');
for ($i = 0; $i < 1000; $i++) {
$writer->startElement('book');
$writer->writeAttribute('id', $i);
$writer->writeElement('title', 'Книга ' . $i);
$writer->endElement();
}
$writer->endElement();
$writer->endDocument();
$writer->flush();
Как выполнять сложные запросы к XML (выборка по условию)?
XPath поддерживается как SimpleXML, так и DOM. Позволяет искать узлы по пути, условиям и атрибутам.
Пример: поиск всех книг с ценой > 500
$xml = simplexml_load_file('catalog.xml');
$books = $xml->xpath("//book[price > 500]");
foreach ($books as $book) {
echo $book->title;
}
Цели и случаи использования каждого подхода
- SimpleXML - для быстрого чтения/записи, когда структура известна и не требуется тонкое управление.
- DOMDocument - для полного контроля над документом, создания сложных структур, валидации.
- XMLReader - для потокового чтения очень больших файлов (десятки мегабайт и выше).
- XMLWriter - для потоковой записи больших файлов без хранения всего содержимого в памяти.
- XPath - для гибкой выборки данных внутри документа.
Расширенные примеры работы с XML в PHP
Пример 1: преобразование XML в ассоциативный массив с помощью SimpleXML и рекурсии
$xml = simplexml_load_string('<users><user id="1"><name>Анна</name><email>anna@example.com</email></user><user id="2"><name>Борис</name><email>boris@example.com</email></user></users>');
function xmlToArray(SimpleXMLElement $xml) {
$result = [];
foreach ($xml->children() as $key => $child) {
$attrs = [];
foreach ($child->attributes() as $attrKey => $attrVal) {
$attrs['@' . $attrKey] = (string)$attrVal;
}
$children = $child->count() ? xmlToArray($child) : (string)$child;
$result[] = $attrs ? array_merge(['@attributes' => $attrs], ['value' => $children]) : $children;
}
return $result;
}
$array = xmlToArray($xml);
print_r($array);
Array
(
[0] => Array
(
[@attributes] => Array
(
[@id] => 1
)
[value] => Array
(
[name] => Анна
[email] => anna@example.com
)
)
[1] => Array
(
[@attributes] => Array
(
[@id] => 2
)
[value] => Array
(
[name] => Борис
[email] => boris@example.com
)
)
)
Пример 2: использование DOMDocument для модификации существующего XML с удалением узлов
$dom = new DOMDocument();
$dom->load('catalog.xml');
$xpath = new DOMXPath($dom);
// Удаляем все книги с ценой меньше 100
$books = $xpath->query("//book[price < 100]");
foreach ($books as $book) {
$book->parentNode->removeChild($book);
}
$dom->save('catalog_updated.xml');
echo 'Файл обновлён';
Файл обновлён
Пример 3: обработка XML с пространствами имён (namespace) через SimpleXML
$xmlString = '<ns:root xmlns:ns="http://example.com/ns"><ns:item id="1">Значение</ns:item></ns:root>';
$xml = simplexml_load_string($xmlString);
$ns = $xml->children('http://example.com/ns');
echo $ns->item['id']; // 1
echo $ns->item; // Значение
Пример 4: валидация XML по XSD-схеме с помощью DOMDocument
$dom = new DOMDocument();
$dom->load('data.xml');
if ($dom->schemaValidate('schema.xsd')) {
echo 'XML корректен';
} else {
echo 'Ошибка валидации';
}
XML корректен
Пример 5: потоковый парсинг с XMLReader и создание SimpleXML-объекта из фрагмента
$reader = new XMLReader();
$reader->open('large.xml');
while ($reader->read()) {
if ($reader->nodeType == XMLREADER::ELEMENT && $reader->localName == 'record') {
$record = simplexml_load_string($reader->readOuterXml());
echo 'ID: ' . $record['id'] . ', Name: ' . $record->name . "\n";
}
}
$reader->close();
ID: 1, Name: Первая запись ID: 2, Name: Вторая запись ...