W3docs

xml_set_element_handler()

Функция xml_set_element_handler() в PHP регистрирует обработчики открывающих и закрывающих тегов XML-элементов.

xml_set_element_handler() регистрирует два обратных вызова на XML-парсере: один срабатывает каждый раз, когда парсер встречает открывающий тег (<book>), другой — на каждом закрывающем теге (</book>). Функция относится к событийно-ориентированному парсеру Expat — семейству xml_parser_* — а не к SimpleXML или DOM. Там, где SimpleXML загружает весь документ в дерево в памяти, Expat потоково проходит по документу и вызывает ваши обработчики по мере обработки, что делает его хорошо подходящим для больших файлов, которые не нужно загружать целиком.

На этой странице рассматриваются сигнатура функции, точные аргументы, которые получают обработчики, полный рабочий пример и типичные ловушки (приведение имён тегов к верхнему регистру и форма обратного вызова через метод объекта).

Синтаксис

xml_set_element_handler(
    XMLParser $parser,
    callable  $start_handler,
    callable  $end_handler
): bool
ПараметрОписание
$parserПарсер, созданный функцией xml_parser_create().
$start_handlerВызывается при каждом открывающем теге. Получает ($parser, $name, $attributes).
$end_handlerВызывается при каждом закрывающем теге. Получает ($parser, $name).

Функция возвращает true в случае успеха и false в случае ошибки. Обратный вызов может быть задан как строка с именем функции ("startTag"), замыкание или пара объект-метод ([$object, 'method']).

Что получают обработчики

  • Обработчик открывающего тега$name содержит имя тега, а $attributes — ассоциативный массив атрибутов этого тега (['ID' => 'b1']).
  • Обработчик закрывающего тега — только $name, поскольку закрывающие теги не несут атрибутов.

По умолчанию Expat приводит имена тегов и атрибутов к верхнему регистру (<book> поступает как BOOK). Сравнивайте имена без учёта регистра или отключите приведение с помощью xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, false). См. xml_parser_set_option().

Примеры использования

Пример: вывод дерева элементов

Этот полный скрипт разбирает XML-строку и использует обработчики начала и конца для вывода отступного контура документа, включая атрибуты каждого тега.

<?php
$xml = '<?xml version="1.0"?>
<library>
  <book id="b1">PHP Basics</book>
  <book id="b2">Advanced XML</book>
</library>';

$depth = 0;

function startTag($parser, $name, $attrs) {
    global $depth;
    echo str_repeat("  ", $depth) . "START: $name";
    foreach ($attrs as $key => $value) {
        echo " ($key=\"$value\")";
    }
    echo "\n";
    $depth++;
}

function endTag($parser, $name) {
    global $depth;
    $depth--;
    echo str_repeat("  ", $depth) . "END:   $name\n";
}

$parser = xml_parser_create();
xml_set_element_handler($parser, "startTag", "endTag");

if (!xml_parse($parser, $xml, true)) {
    die(sprintf(
        "XML error: %s at line %d",
        xml_error_string(xml_get_error_code($parser)),
        xml_get_current_line_number($parser)
    ));
}

xml_parser_free($parser);

Вывод:

START: LIBRARY
  START: BOOK (ID="b1")
  END:   BOOK
  START: BOOK (ID="b2")
  END:   BOOK
END:   LIBRARY

Обратите внимание: library поступает как LIBRARY, а id — как ID: это то самое приведение к верхнему регистру, упомянутое выше. Третий аргумент xml_parse() установлен в true, чтобы сообщить парсеру, что это последний (и единственный) фрагмент данных. Всегда освобождайте парсер с помощью xml_parser_free() по завершении работы.

Пример: использование метода объекта в качестве обработчика

Обработчики не обязаны быть обычными функциями. Передача [$object, 'method'] позволяет хранить состояние разбора в объекте, а не в глобальных переменных — что удобно, когда нескольким обработчикам нужно совместно использовать данные.

<?php
$xml = '<note><to>Tove</to><from>Jani</from></note>';

class TagCounter {
    public int $open = 0;
    public function onStart($parser, $name, $attrs) { $this->open++; }
    public function onEnd($parser, $name) {}
}

$counter = new TagCounter();
$parser  = xml_parser_create();
xml_set_element_handler($parser, [$counter, 'onStart'], [$counter, 'onEnd']);
xml_parse($parser, $xml, true);
xml_parser_free($parser);

echo "Opening tags seen: {$counter->open}\n";

Вывод:

Opening tags seen: 3

Когда использовать

Используйте обработчики Expat, когда вам нужен потоковый, малопамятный проход по XML — большие фиды, лог-файлы или карты сайта — или когда вас интересуют лишь несколько тегов и вы не хотите строить полное дерево. Чтобы считывать текст внутри элемента (например, PHP Basics в <book>PHP Basics</book>), используйте эту функцию совместно с xml_set_character_data_handler(). Если вы предпочитаете работать с небольшим документом через XPath-подобный доступ, SimpleXML будет проще. Для обзора всех подходов см. PHP XML Parsers.

Заключение

xml_set_element_handler() подключает обратные вызовы для начального и конечного тегов к событийно-ориентированному парсеру Expat в PHP, позволяя реагировать на структуру документа по мере его потоковой обработки. Помните о трёх ключевых моментах: сначала создайте парсер, учитывайте приведение имён тегов к верхнему регистру и освобождайте парсер по завершении.

Практика

Практика
Для чего используется функция xml_set_element_handler() в PHP?
Для чего используется функция xml_set_element_handler() в PHP?
Was this page helpful?