Xml set start namespace decl handler: примеры (PHP)

Практическое применение xml_set_start_namespace_decl_handler в PHP
Раздел: XML
xml_set_start_namespace_decl_handler(resource parser, callable handler): bool

Базовая информация о функции xml_set_start_namespace_decl_handler

Функция xml_set_start_namespace_decl_handler является частью XML-парсера в PHP и используется для установки обработчика, вызываемого при обнаружении объявления пространства имен в начале элемента при разборе XML-документа. Эта функция применяется при необходимости обрабатывать объявления пространств имен, такие как xmlns:prefix='URI', в процессе парсинга XML с использованием библиотеки Expat.

Аргументы функции
  • parser (обязательный): ссылка на XML-парсер, созданный с помощью xml_parser_create() или xml_parser_create_ns().
  • handler (обязательный): имя функции обратного вызова (callback), которая будет вызываться при обнаружении объявления пространства имен. Функция должна принимать три параметра: $parser (парсер), $prefix (префикс пространства имен) и $uri (URI пространства имен). Если префикс отсутствует (например, в случае пространства имен по умолчанию), $prefix будет пустой строкой.

Функция возвращает true при успешной установке обработчика и false в случае неудачи.

Короткие примеры использования

Пример 1: Базовый обработчик пространств имен
<?php
function startNamespaceHandler($parser, $prefix, $uri) {
    echo "Начало пространства имен: префикс = '$prefix', URI = '$uri'\n";
}

$xml = '<root xmlns:books="http://example.org/books"><books:title/></root>';
$parser = xml_parser_create_ns();
xml_set_start_namespace_decl_handler($parser, 'startNamespaceHandler');
xml_parse($parser, $xml, true);
xml_parser_free($parser);
?>
Начало пространства имен: префикс = 'books', URI = 'http://example.org/books'
Пример 2: Обработка пространства имен по умолчанию
<?php
function startNamespaceHandler($parser, $prefix, $uri) {
    if ($prefix === '') {
        echo "Пространство имен по умолчанию: URI = '$uri'\n";
    } else {
        echo "Префиксное пространство имен: префикс = '$prefix', URI = '$uri'\n";
    }
}

$xml = '<root xmlns="http://example.org/default" xmlns:test="http://example.org/test"><child/></root>';
$parser = xml_parser_create_ns();
xml_set_start_namespace_decl_handler($parser, 'startNamespaceHandler');
xml_parse($parser, $xml, true);
xml_parser_free($parser);
?>
Пространство имен по умолчанию: URI = 'http://example.org/default'
Префиксное пространство имен: префикс = 'test', URI = 'http://example.org/test'

Похожие функции в PHP

В PHP существуют альтернативные функции для работы с XML, которые могут обрабатывать пространства имен:

  • xml_set_end_namespace_decl_handler: устанавливает обработчик, вызываемый при завершении объявления пространства имен. Используется реже, так как объявления пространств имен обычно обрабатываются при их начале.
  • DOMDocument: объектно-ориентированный подход для разбора XML, включая методы для работы с пространствами имен (например, getElementsByTagNameNS). Рекомендуется для сложных операций с XML, так как предоставляет больше возможностей и удобства.
  • SimpleXMLchildren() и attributes() с указанием URI пространства имен. Подходит для быстрого доступа к данным XML.

Функция xml_set_start_namespace_decl_handler предпочтительнее при потоковом разборе больших XML-документов с минимальным использованием памяти, в то время как DOMDocument и SimpleXML загружают весь документ в память.

Альтернативы в других языках программирования

Python: xml.sax.handler.startPrefixMapping
import xml.sax

class NamespaceHandler(xml.sax.ContentHandler):
    def startPrefixMapping(self, prefix, uri):
        print(f"Начало пространства имен: префикс = '{prefix}', URI = '{uri}'")

handler = NamespaceHandler()
parser = xml.sax.make_parser()
parser.setContentHandler(handler)
parser.parseString('<root xmlns:books="http://example.org/books"><books:title/></root>')
Начало пространства имен: префикс = 'books', URI = 'http://example.org/books'
JavaScript: обработка пространств имен в SAX-парсерах
const sax = require('sax');
const parser = sax.parser(true);
parser.onopennamespace = function(ns) {
    console.log(`Начало пространства имен: префикс = '${ns.prefix}', URI = '${ns.uri}'`);
};
parser.write('<root xmlns:books="http://example.org/books"><books:title/></root>');
Начало пространства имен: префикс = 'books', URI = 'http://example.org/books'

Основное отличие: в Python и JavaScript используются объектно-ориентированные подходы, в то время как в PHP функция является процедурной и требует явной установки обработчиков.

Типичные ошибки при использовании

Ошибка 1: Неправильное создание парсера
<?php
function startNamespaceHandler($parser, $prefix, $uri) {
    echo "Пространство имен: $prefix -> $uri\n";
}

$parser = xml_parser_create(); // Создан без поддержки пространств имен
xml_set_start_namespace_decl_handler($parser, 'startNamespaceHandler'); // Ошибка: обработчик не будет вызван
$xml = '<root xmlns:test="http://example.org"></root>';
xml_parse($parser, $xml, true);
?>
// Объявления пространств имен не обрабатываются, ошибок не возникает, но обработчик не вызывается
Ошибка 2: Некорректное имя функции обратного вызова
<?php
$parser = xml_parser_create_ns();
xml_set_start_namespace_decl_handler($parser, 'nonExistentFunction'); // Функция не существует
$xml = '<root xmlns:test="http://example.org"></root>';
xml_parse($parser, $xml, true); // Вызовет предупреждение
?>
Warning: xml_set_start_namespace_decl_handler(): Invalid handler

Изменения в последних версиях PHP

В PHP 8 функция xml_set_start_namespace_decl_handler не претерпела значительных изменений. Однако, начиная с PHP 8.0, все функции XML Expat теперь выбрасывают исключения типа ValueError при передаче неверных аргументов вместо генерации предупреждений. Например, передача некорректного ресурса парсера вызовет исключение.

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

Пример 1: Сбор всех пространств имен в массиве
Пример php
<?php
$namespaces = [];
function collectNamespaces($parser, $prefix, $uri) {
    global $namespaces;
    $namespaces[$prefix] = $uri;
}

$xml = '<root xmlns="http://default.org" xmlns:a="http://a.org" xmlns:b="http://b.org">';
$parser = xml_parser_create_ns();
xml_set_start_namespace_decl_handler($parser, 'collectNamespaces');
xml_parse($parser, $xml, true);
print_r($namespaces);
?>
Array
(
    [default] => http://default.org
    [a] => http://a.org
    [b] => http://b.org
)
Пример 2: Валидация URI пространств имен
Пример php
<?php
function validateNamespaceUri($parser, $prefix, $uri) {
    if (!filter_var($uri, FILTER_VALIDATE_URL)) {
        echo "Некорректный URI для префикса '$prefix': $uri\n";
    } else {
        echo "Корректный URI для префикса '$prefix'\n";
    }
}

$xml = '<root xmlns:valid="https://example.org" xmlns:invalid="not-a-url"></root>';
$parser = xml_parser_create_ns();
xml_set_start_namespace_decl_handler($parser, 'validateNamespaceUri');
xml_parse($parser, $xml, true);
?>
Корректный URI для префикса 'valid'
Некорректный URI для префикса 'invalid': not-a-url
Пример 3: Обработка вложенных пространств имен
Пример php
<?php
function logNamespaceStart($parser, $prefix, $uri) {
    $depth = xml_get_current_line_number($parser); // Используем номер строки как индикатор глубины
    echo "Глубина $depth: начало пространства имен '$prefix' -> '$uri'\n";
}

$xml = '<root xmlns:outer="http://outer"><child xmlns:inner="http://inner"></child></root>';
$parser = xml_parser_create_ns();
xml_set_start_namespace_decl_handler($parser, 'logNamespaceStart');
xml_parse($parser, $xml, true);
?>
Глубина 1: начало пространства имен 'outer' -> 'http://outer'
Глубина 1: начало пространства имен 'inner' -> 'http://inner'

PHP xml_set_start_namespace_decl_handler function comments

En
Xml set start namespace decl handler Set up start namespace declaration handler