xml_set_end_namespace_decl_handler()
Функция xml_set_end_namespace_decl_handler() в PHP регистрирует пользовательский обработчик для конца объявлений пространств имён XML.
Функция xml_set_end_namespace_decl_handler() — это встроенная функция PHP, которая регистрирует пользовательский обратный вызов, срабатывающий при достижении SAX XML-парсером конца элемента, объявившего одно или несколько XML-пространств имён. Она является закрывающим аналогом xml_set_start_namespace_decl_handler(): стартовый обработчик срабатывает, когда префикс пространства имён входит в область видимости, а этот конечный обработчик — когда этот префикс выходит из неё.
Данная функция относится к событийно-ориентированному (SAX) расширению xml PHP, которое читает документ сверху вниз и вызывает обработчики по мере обнаружения каждой конструкции, вместо построения дерева в памяти, как это делает SimpleXML. Она наиболее полезна, когда нужно отслеживать, какие пространства имён активны в процессе разбора — например, для ведения стека активных префиксов или очистки состояния по завершении раздела с пространствами имён.
Когда использовать
Объявление пространства имён — это атрибут вида xmlns:ns="http://example.com". Его область видимости распространяется на элемент, в котором он объявлен, и на всех его потомков. Используйте конечный обработчик пространства имён, когда нужно знать точный момент закрытия этой области видимости — как правило, чтобы извлечь префикс из стека, сформированного стартовым обработчиком, зеркально отражая управление областью видимости самим парсером.
Синтаксис
xml_set_end_namespace_decl_handler(XMLParser $parser, callable|false $handler): bool| Параметр | Описание |
|---|---|
$parser | XML-парсер, созданный с помощью xml_parser_create_ns() (рекомендуется) или xml_parser_create(). |
$handler | Обратный вызов, выполняемый при каждом событии конца пространства имён, или false для удаления ранее установленного обработчика. |
Возвращаемое значение: возвращает true при успехе и false при неудаче (например, если $parser не является допустимым парсером).
Обработчик получает два аргумента:
function handler(XMLParser $parser, string $prefix): void$prefix — префикс пространства имён, область видимости которого завершается (пустая строка "" для объявления по умолчанию xmlns="..."). Обратите внимание, что в отличие от стартового обработчика, конечный обработчик не получает URI пространства имён — только префикс.
Примеры использования
Пример: установка обработчика конца объявления пространства имён
В этом примере устанавливается обработчик и он запускается путём разбора небольшой XML-строки. Обработчик вызывается во время xml_parse(), когда парсер закрывает элемент, объявивший пространство имён.
Разбор XML с обработчиком конца объявления пространства имён
function handle_end_namespace_decl($parser, $prefix) {
echo "End of namespace prefix: $prefix\n";
}
$xml_parser = xml_parser_create_ns();
xml_set_end_namespace_decl_handler($xml_parser, "handle_end_namespace_decl");
$xml_data = '<?xml version="1.0"?><root xmlns:ns="http://example.com"><ns:child/></root>';
xml_parse($xml_parser, $xml_data, true);
xml_parser_free($xml_parser);Префикс ns объявлен на <root>, поэтому его область видимости заканчивается при достижении </root>. Когда срабатывает обработчик, он выводит префикс, выходящий из области видимости:
End of namespace prefix: nsВажно: срабатывание конечного обработчика пространства имён зависит от используемой сборки
libexpat/PHP — в некоторых версиях PHP стартовый обработчик работает, а конечный — нет. Всегда проверяйте поведение в целевой среде выполнения и никогда не полагайтесь только на конечный обработчик для обнаружения пространств имён; используйте его совместно со стартовым обработчиком (ниже), чтобы состояние оставалось согласованным.
Пример: совместное использование стартового и конечного обработчиков для отслеживания области видимости
В реальных парсерах конечный обработчик редко используется отдельно. Совместное применение его со стартовым позволяет поддерживать стек префиксов, активных в данный момент. Стартовый обработчик добавляет каждый префикс при его входе в область видимости; конечный — извлекает его при закрытии объявляющего элемента:
Отслеживание активных префиксов пространств имён с помощью стека
$activePrefixes = [];
function on_start_ns($parser, $prefix, $uri) {
global $activePrefixes;
$activePrefixes[] = $prefix;
echo "Enter '$prefix' -> $uri | active: " . implode(', ', $activePrefixes) . "\n";
}
function on_end_ns($parser, $prefix) {
global $activePrefixes;
array_pop($activePrefixes);
echo "Leave '$prefix' | active: " . implode(', ', $activePrefixes) . "\n";
}
$parser = xml_parser_create_ns();
xml_set_start_namespace_decl_handler($parser, "on_start_ns");
xml_set_end_namespace_decl_handler($parser, "on_end_ns");
$xml = '<?xml version="1.0"?>'
. '<a xmlns:x="urn:x"><b xmlns:y="urn:y"><c/></b></a>';
xml_parse($parser, $xml, true);
xml_parser_free($parser);Префикс x объявлен на <a>, а y — на вложенном <b>. По мере открытия и закрытия областей видимости стек отслеживает, какие префиксы активны в данный момент. Конечные события срабатывают в порядке «последним вошёл, первым вышел» — y (внутренний) выходит из области видимости раньше x:
Enter 'x' -> urn:x | active: x
Enter 'y' -> urn:y | active: x, y
Leave 'y' | active: x
Leave 'x' | active: Этот паттерн добавления/извлечения из стека является каноническим способом использования конечного обработчика: он синхронизирует ваше представление об активных пространствах имён с собственным управлением областью видимости парсера.
Частые ошибки
- Используйте
xml_parser_create_ns(). Обработчики пространств имён получают события только при использовании парсера, поддерживающего пространства имён. Парсер, созданный с помощью обычнойxml_parser_create(), не будет разделять префиксы и URI. - URI отсутствует в конечном обратном вызове. Если URI нужен при закрытии области видимости, сохраните его в стартовом обработчике (с ключом по префиксу) и обращайтесь к нему здесь.
- Устанавливайте обработчики до начала разбора. Зарегистрируйте обработчик перед первым вызовом
xml_parse(); обработчики, установленные в процессе разбора, пропустят более ранние события. - Освобождайте парсер. Вызывайте
xml_parser_free()по завершении работы для освобождения ресурсов, особенно в долгоработающих скриптах.
Заключение
xml_set_end_namespace_decl_handler() позволяет SAX-парсеру точно сообщать вашему коду, когда префикс XML-пространства имён выходит из области видимости. В сочетании с xml_set_start_namespace_decl_handler() и поддерживающим пространства имён парсером из xml_parser_create_ns() это даёт вам точный, малоёмкий контроль над областью видимости пространств имён при потоковой обработке больших XML-документов.