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 Worldxml_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; эта функция актуальна при поддержке существующих парсеров или потоковой обработке очень больших документов.