Работа с 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>