Xml parse into struct: примеры (PHP)
xml_parse_into_struct(resource parser, string data, array &values [, array &index]): intФункция xml_parse_into_struct() используется в PHP для синтаксического разбора XML-документа с сохранением его структуры в массивы. Она часто применяется при необходимости программного анализа XML-данных без использования DOM-модели или SimpleXML. Функция работает вместе с xml_parser_create() и xml_parse().
- parser (обязательный): Ссылка на XML-парсер, созданный функцией xml_parser_create().
- data (обязательный): Строка, содержащая XML-данные для разбора. Разбор может происходить по частям.
- &$values (обязательный): Переменная, передаваемая по ссылке. После выполнения функции содержит массив значений элементов XML.
- &$index (необязательный): Переменная, передаваемая по ссылке. Содержит ассоциативный массив, где ключи - имена тегов, а значения - массив индексов в $values.
Функция возвращает 1 при успешном разборе или 0 в случае ошибки.
<?php
$xml_data = '<book><title>PHP Guide</title><author>John Doe</author></book>';
$parser = xml_parser_create();
xml_parse_into_struct($parser, $xml_data, $values);
xml_parser_free($parser);
print_r($values);
?>Array
(
[0] => Array
(
[tag] => BOOK
[type] => open
[level] => 1
)
[1] => Array
(
[tag] => TITLE
[type] => complete
[level] => 2
[value] => PHP Guide
)
[2] => Array
(
[tag] => AUTHOR
[type] => complete
[level] => 2
[value] => John Doe
)
[3] => Array
(
[tag] => BOOK
[type] => close
[level] => 1
)
)<?php
$xml_data = '<books><book id="1">First</book><book id="2">Second</book></books>';
$parser = xml_parser_create();
xml_parse_into_struct($parser, $xml_data, $values, $index);
xml_parser_free($parser);
echo "Values:\n";
print_r($values);
echo "\nIndex:\n";
print_r($index);
?>Values:
Array
(
[0] => Array
(
[tag] => BOOKS
[type] => open
[level] => 1
)
[1] => Array
(
[tag] => BOOK
[type] => complete
[level] => 2
[value] => First
[attributes] => Array
(
[ID] => 1
)
)
[2] => Array
(
[tag] => BOOK
[type] => complete
[level] => 2
[value] => Second
[attributes] => Array
(
[ID] => 2
)
)
[3] => Array
(
[tag] => BOOKS
[type] => close
[level] => 1
)
)
Index:
Array
(
[BOOKS] => Array
(
[0] => 0
[1] => 3
)
[BOOK] => Array
(
[0] => 1
[1] => 2
)
)В PHP существует несколько альтернативных способов работы с XML:
Расширение SimpleXML предоставляет простой объектно-ориентированный интерфейс для преобразования XML в объект. Подходит для чтения и изменения XML-данных с простой структурой.
$xml = simplexml_load_string('<root><item>Test</item></root>');
echo $xml->item;Расширение DOM реализует полную модель DOM (Document Object Model). Оно подходит для сложных операций: создания, модификации, валидации XML-документов. Требует больше памяти, но предоставляет полный контроль.
$dom = new DOMDocument();
$dom->loadXML('<root><item>Test</item></root>');
echo $dom->getElementsByTagName('item')[0]->nodeValue;XMLReader обеспечивает последовательный pull-парсинг. Эффективен для обработки больших XML-файлов, так как не загружает весь документ в память.
$reader = new XMLReader();
$reader->xml('<root><item>Test</item></root>');
while($reader->read()) {
if ($reader->nodeType == XMLReader::ELEMENT && $reader->name == 'item') {
echo $reader->readString();
}
}Выбор зависит от задачи: xml_parse_into_struct удобна для быстрого преобразования в массив, SimpleXML - для простого доступа, DOMDocument - для манипуляций, XMLReader - для потоковой обработки больших данных.
Модуль ElementTree предоставляет простой API для парсинга и создания XML. Результат часто представляется в виде дерева объектов.
import xml.etree.ElementTree as ET
data = '<book><title>Python Guide</title></book>'
root = ET.fromstring(data)
print(root.find('title').text)Python Guide
В браузерном JavaScript для разбора XML используется объект DOMParser, который создает DOM-дерево.
const parser = new DOMParser();
const xmlDoc = parser.parseFromString('<book><title>JS Guide</title></book>', 'text/xml');
console.log(xmlDoc.getElementsByTagName('title')[0].textContent);JS Guide
MySQL предоставляет функцию ExtractValue() для извлечения данных из XML-строк с использованием XPath. Работает только с подстрокой XML.
SELECT ExtractValue('<book><title>MySQL XML</title></book>', '/book/title');MySQL XML
Отличие от PHP функции в том, что альтернативы обычно работают с объектными моделями или деревьями, а xml_parse_into_struct возвращает плоский массив со структурной информацией.
Если кодировка XML-данных не совпадает с кодировкой парсера, символы могут отображаться некорректно.
$xml_data = '<root><item>Тест</item></root>';
$parser = xml_parser_create('UTF-8'); // XML в windows-1251
xml_parse_into_struct($parser, $xml_data, $values);
print_r($values);// Значения могут быть искажены
Функция возвращает 0 при синтаксических ошибках в XML, но не генерирует исключений. Нужно проверять результат.
$xml_data = '<root><item>Test';
$parser = xml_parser_create();
$result = xml_parse_into_struct($parser, $xml_data, $values);
if ($result === 0) {
echo 'Ошибка парсинга: ' . xml_error_string(xml_get_error_code($parser));
}Ошибка парсинга: Mismatched tag
Попытка использовать парсер после вызова xml_parser_free() приводит к неопределенному поведению.
$parser = xml_parser_create();
xml_parser_free($parser);
xml_parse_into_struct($parser, '<test/>', $values); // ОшибкаФункция xml_parse_into_struct() остается стабильной и не претерпела значительных изменений в последних основных версиях PHP, включая PHP 8.x. Однако, в рамках общего развития XML-расширения, могли происходить изменения в связанных функциях, таких как xml_parser_create().
Важным аспектом для PHP 8 является усиление типизации. Аргументы функции ожидают определенных типов, и их несоответствие может вызывать TypeError. В отличие от предыдущих версий, где могло происходить неявное преобразование.
// В PHP 8 это вызовет TypeError, если parser не является ресурсом (xml).
// В PHP 7 могло работать с предупреждением.
xml_parse_into_struct('not_a_parser', '<test/>', $values);Рекомендуется всегда использовать функцию с корректно созданным парсером и проверять типы передаваемых данных.
Функция позволяет парсить XML частями, что полезно для работы с большими файлами.
<?php
$parser = xml_parser_create();
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0); // Отключаем приведение к верхнему регистру
$values = [];
$index = [];
function chunk_parser($fp, $parser, &$values, &$index) {
while ($data = fread($fp, 4096)) {
if (!xml_parse_into_struct($parser, $data, $chunk_vals, $chunk_idx)) {
die('Ошибка парсинга');
}
// Здесь можно обрабатывать $chunk_vals постепенно
}
}
$fp = fopen('large.xml', 'r');
chunk_parser($fp, $parser, $values, $index);
fclose($fp);
xml_parser_free($parser);
?>На основе массива $values можно восстановить древовидную структуру XML.
<?php
$xml = '<catalog><book id="1"><title>Title1</title></book><book id="2"><title>Title2</title></book></catalog>';
$parser = xml_parser_create();
xml_parse_into_struct($parser, $xml, $vals, $index);
xml_parser_free($parser);
$tree = [];
$stack = [];
foreach ($vals as $val) {
if ($val['type'] == 'open' || $val['type'] == 'complete') {
$node = ['tag' => $val['tag']];
if (isset($val['attributes'])) $node['attributes'] = $val['attributes'];
if (isset($val['value'])) $node['value'] = $val['value'];
$node['children'] = [];
if (empty($stack)) {
$tree[] = &$node;
} else {
$last_idx = count($stack) - 1;
$stack[$last_idx]['children'][] = &$node;
}
if ($val['type'] == 'open') {
$stack[] = &$node;
}
} elseif ($val['type'] == 'close') {
array_pop($stack);
}
}
print_r($tree);
?>Array
(
[0] => Array
(
[tag] => CATALOG
[children] => Array
(
[0] => Array
(
[tag] => BOOK
[attributes] => Array
(
[ID] => 1
)
[children] => Array
(
[0] => Array
(
[tag] => TITLE
[value] => Title1
[children] => Array
( )
)
)
)
[1] => Array
(
[tag] => BOOK
[attributes] => Array
(
[ID] => 2
)
[children] => Array
(
[0] => Array
(
[tag] => TITLE
[value] => Title2
[children] => Array
( )
)
)
)
)
)
)Использование массива $index для быстрого доступа к элементам с определенным тегом.
<?php
$xml = '<data><item>A</item><info>B</info><item>C</item></data>';
$parser = xml_parser_create();
xml_parse_into_struct($parser, $xml, $vals, $index);
xml_parser_free($parser);
if (isset($index['ITEM'])) {
echo 'Найдены элементы ITEM по индексам: ' . implode(', ', $index['ITEM']) . "\n";
foreach ($index['ITEM'] as $pos) {
echo "Значение: " . $vals[$pos]['value'] . "\n";
}
}
?>Найдены элементы ITEM по индексам: 1, 3 Значение: A Значение: C