Xml parse into struct: примеры (PHP)

Парсинг XML данных функцией xml_parse_into_struct
Раздел: XML
xml_parse_into_struct(resource parser, string data, array &values [, array &index]): int
Описание функции xml_parse_into_struct

Функция 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 в случае ошибки.

Примеры использования xml_parse_into_struct
Простой разбор XML в массив
<?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
        )
)
Использование параметра index
<?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

В PHP существует несколько альтернативных способов работы с XML:

SimpleXML

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

$xml = simplexml_load_string('<root><item>Test</item></root>');
echo $xml->item;
DOMDocument

Расширение DOM реализует полную модель DOM (Document Object Model). Оно подходит для сложных операций: создания, модификации, валидации XML-документов. Требует больше памяти, но предоставляет полный контроль.

$dom = new DOMDocument();
$dom->loadXML('<root><item>Test</item></root>');
echo $dom->getElementsByTagName('item')[0]->nodeValue;
XMLReader

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 - для потоковой обработки больших данных.

Альтернативы в других языках
Python: xml.etree.ElementTree

Модуль 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: DOMParser

В браузерном 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

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);
// Значения могут быть искажены
Попытка разбора битых XML-данных

Функция возвращает 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); // Ошибка
Изменения в последних версиях PHP

Функция 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-файлов по частям

Функция позволяет парсить XML частями, что полезно для работы с большими файлами.

Пример php
<?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
<?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
<?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

PHP xml_parse_into_struct function comments

En
Xml parse into struct Parse XML data into an array structure