W3docs

xml_set_character_data_handler()

Функция xml_set_character_data_handler() регистрирует пользовательский обработчик символьных данных в XML-парсере PHP.

Функция xml_set_character_data_handler() регистрирует пользовательский обратный вызов, который XML-парсер вызывает каждый раз при обнаружении символьных данных — текстового содержимого, расположенного между XML-тегами. Она относится к устаревшему расширению xml, которое оборачивает событийный парсер Expat, и является частью потокового («SAX-стилевого») API разбора PHP в отличие от древовидных подходов DOMDocument или SimpleXML.

Эта функция используется тогда, когда нужно захватить или преобразовать текст внутри элементов по мере потокового прохождения документа — например, для сбора заголовка каждого элемента <item> в RSS-ленте или для преобразования извлечённого текста без построения всего документа в памяти. Она почти всегда используется совместно с xml_set_element_handler(), которая сообщает, к какому элементу относится данный текст.

Обратите внимание: Расширение xml является устаревшим. Для нового кода предпочтительнее использовать SimpleXML или DOMDocument. Используйте этот обработчик при поддержке существующих парсеров на основе Expat или когда действительно необходима событийная потоковая обработка очень больших документов.

Синтаксис

xml_set_character_data_handler(XMLParser $parser, callable $handler): bool
  • $parser — парсер, созданный функцией xml_parser_create().
  • $handler — обратный вызов для символьных данных. Передаётся имя функции в виде строки, замыкание или массив для метода. Передача пустой строки "" отменяет ранее зарегистрированный обработчик.

При успешном выполнении функция возвращает true.

Сигнатура обработчика

Обработчик принимает два аргумента — парсер и фрагмент текста:

function handler(XMLParser $parser, string $data): void

В более старой документации иногда упоминается третий параметр $length, однако расширение xml на основе Expat его не передаёт. В PHP 8+ объявление третьего обязательного параметра вызывает ArgumentCountError, поэтому ограничьте обработчик двумя параметрами (или сделайте дополнительные необязательными).

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

Пример 1: Минимальный обработчик символьных данных

Создайте парсер, подключите обработчик, затем передайте ему XML-строку. Обработчик просто выводит обрезанный текст:

function handle_character_data($parser, $data) {
    echo trim($data);
}

$xml_parser = xml_parser_create();
xml_set_character_data_handler($xml_parser, "handle_character_data");

$xml_data = '<root><item>Hello World</item></root>';
xml_parse($xml_parser, $xml_data, true);

xml_parser_free($xml_parser);
// Output: Hello World

xml_parser_create() создаёт парсер, xml_set_character_data_handler() подключает обратный вызов, xml_parse() передаёт данные (последний аргумент true означает конец данных), а xml_parser_free() освобождает парсер.

Особенность фрагментации вызовов

Парсер может вызывать обработчик несколько раз для одного элемента, а также вызывает его для пробельных символов между элементами. Он не передаёт одну аккуратную строку на элемент. Посмотрите, что происходит с двумя элементами и отступами:

function show($parser, $data) {
    echo '[' . $data . "]\n";
}

$p = xml_parser_create();
xml_set_character_data_handler($p, "show");

$xml = '<root><item>Hello World</item>  <item>Goodbye</item></root>';
xml_parse($p, $xml, true);
xml_parser_free($p);

// Output:
// [Hello World]
// [  ]
// [Goodbye]

Два пробела между </item> и следующим <item> вызывают отдельный вызов обработчика. Длинный текст также может поступать разбитым на несколько вызовов. По этой причине следует буферизовать данные и обрабатывать их только после завершения элемента.

Пример 2: Буферизация текста с обработчиком элементов

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

$buffer = '';

function start_element($parser, $name, $attrs) {
    global $buffer;
    $buffer = '';            // start collecting fresh text
}

function character_data($parser, $data) {
    global $buffer;
    $buffer .= $data;        // chunks may arrive in pieces — append
}

function end_element($parser, $name) {
    global $buffer;
    $text = trim($buffer);
    if ($text !== '') {
        echo "$name: $text\n";
    }
}

$parser = xml_parser_create();
xml_set_element_handler($parser, "start_element", "end_element");
xml_set_character_data_handler($parser, "character_data");

$xml = '<books><title>PHP Basics</title><title>Advanced XML</title></books>';
xml_parse($parser, $xml, true);
xml_parser_free($parser);

// Output:
// TITLE: PHP Basics
// TITLE: Advanced XML

Имена элементов по умолчанию приводятся к верхнему регистру, поскольку парсер выполняет складывание регистра. Для сохранения исходного регистра отключите складывание с помощью xml_parser_set_option():

xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);

Распространённые ошибки

  • Предположение об одном вызове на элемент. Как показано выше, символьные данные могут поступать несколькими фрагментами; всегда накапливайте их в буфере.
  • Вызовы только с пробельными символами. Отступы и переносы строк между тегами также вызывают обработчик. Фильтруйте их с помощью trim() перед обработкой.
  • Третий параметр обработчика. Обработчик Expat передаёт только $parser и $data; обязательный параметр $length вызовет ArgumentCountError.
  • Регистрация обработчика после начала разбора. Подключайте все обработчики до вызова xml_parse(), иначе события уже будут пропущены.

Заключение

xml_set_character_data_handler() регистрирует обратный вызов для текста между XML-тегами в устаревшем расширении xml PHP на основе Expat. Обработчик принимает два аргумента — парсер и фрагмент данных — и может вызываться многократно для одного элемента, в том числе для пробельных символов. Поэтому надёжный подход — буферизация текста с последующей обработкой по окончании элемента через xml_set_element_handler(). Для новых проектов предпочтительнее использовать современные API SimpleXML или DOMDocument; эта функция актуальна при поддержке существующих парсеров или потоковой обработке очень больших документов.

Практика

Практика
Что делает функция 'xml_set_character_data_handler()' в PHP?
Что делает функция 'xml_set_character_data_handler()' в PHP?
Was this page helpful?