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

Использование xml_set_notation_decl_handler для разбора нотаций XML
Раздел: XML
xml_set_notation_decl_handler(resource parser, callable handler): bool
Описание xml_set_notation_decl_handler

Функция xml_set_notation_decl_handler() в PHP устанавливает обработчик объявлений нотации (NOTATION) в XML-документе при использовании XML-парсера на основе библиотеки Expat.

Использование происходит в момент, когда требуется обработать объявления NOTATION в DTD (Document Type Definition) документа XML. NOTATION определяет форматы данных, не являющиеся XML, например, двоичные форматы изображений.

Аргументы функции

Функция принимает два аргумента:

  1. parser (resource) - ссылка на XML-парсер, созданный функцией xml_parser_create().
  2. handler (callable) - имя функции-обработчика, которая будет вызвана при обнаружении объявления нотации. Обработчик должен принимать пять аргументов:
    • parser - ссылка на парсер.
    • notation_name - имя нотации.
    • base - базовый URI для разрешения системного идентификатора (может быть пустой строкой).
    • system_id - системный идентификатор.
    • public_id - публичный идентификатор.
Краткие примеры использования

Пример с обработчиком в виде именованной функции:

<?php
function notationHandler($parser, $notationName, $base, $systemId, $publicId) {
    echo "Обнаружена нотация: $notationName\n";
}

$xmlParser = xml_parser_create();
xml_set_notation_decl_handler($xmlParser, "notationHandler");

$xml = '<!DOCTYPE doc [
    <!NOTATION gif SYSTEM "image/gif">
]>
<doc/>';

xml_parse($xmlParser, $xml, true);
xml_parser_free($xmlParser);
?>
Обнаружена нотация: gif

Пример с анонимной функцией:

<?php
$xmlParser = xml_parser_create();
xml_set_notation_decl_handler($xmlParser, function($parser, $name, $base, $sys, $pub) {
    echo "Нотация $name: $sys\n";
});

$xml = '<?xml version="1.0"?>
<!DOCTYPE doc [
    <!NOTATION jpeg PUBLIC "-//ISO//NOTATION JPEG//EN" "image/jpeg">
]>
<doc/>';

xml_parse($xmlParser, $xml, true);
xml_parser_free($xmlParser);
?>
Нотация jpeg: image/jpeg
Похожие функции в PHP

Для работы с XML в PHP существуют несколько подходов:

XML Parser функции

xml_set_element_handler() - устанавливает обработчики начальных и конечных тегов. Используется вместе с xml_set_notation_decl_handler для полного разбора.

DOMDocument

Класс DOMDocument предоставляет более высокоуровневый API для работы с XML. Он автоматически обрабатывает DTD и нотации при загрузке документа. Предпочтительнее для манипуляций с документом.

SimpleXML

Расширение SimpleXML предназначено для быстрого доступа к данным XML, но не поддерживает работу с DTD и нотациями.

Выбор зависит от задачи: Expat-парсер (включая xml_set_notation_decl_handler) используется для потокового разбора больших файлов, DOMDocument - для полного разбора и манипуляций, SimpleXML - для простого чтения данных.

Альтернативы в других языках
Python: xml.sax
import xml.sax

class NotationHandler(xml.sax.handler.ContentHandler):
    def notationDecl(self, name, public_id, system_id):
        print(f"Notation: {name}, System: {system_id}")

parser = xml.sax.make_parser()
parser.setContentHandler(NotationHandler())
parser.parse("data.xml")
JavaScript: DOMParser
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(`
<!DOCTYPE doc [
    <!NOTATION png SYSTEM "image/png">
]>
<doc/>`, "text/xml");
// Нотации доступны через xmlDoc.doctype.notations

Xml set notation decl handler в MySQL

MySQL не имеет прямой аналогии, так как не предназначен для разбора XML на низком уровне. Функции типа ExtractValue работают с данными XML, но не с DTD.

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

Типичные ошибки
Несуществующий обработчик
<?php
$parser = xml_parser_create();
xml_set_notation_decl_handler($parser, "nonExistentFunction");
$xml = '<!DOCTYPE doc [<!NOTATION test SYSTEM "">]><doc/>';
xml_parse($parser, $xml, true);
?>
Warning: xml_parse(): Unable to call handler notation declaration handler in ...
Неправильная сигнатура обработчика
<?php
function handler($parser) { } // Недостаточно параметров
$parser = xml_parser_create();
xml_set_notation_decl_handler($parser, "handler");
$xml = '<!DOCTYPE doc [<!NOTATION a SYSTEM "">]><doc/>';
xml_parse($parser, $xml, true);
?>
Warning: xml_parse(): Notation declaration handler expects 5 parameters, 1 given in ...
Попытка использования после освобождения парсера
<?php
$parser = xml_parser_create();
xml_parser_free($parser);
xml_set_notation_decl_handler($parser, "handler"); // Предупреждение
?>
Warning: xml_set_notation_decl_handler(): supplied argument is not a valid XML Parser resource in ...
Изменения в последних версиях PHP

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

<?php
// PHP 7: Warning
// PHP 8: TypeError
try {
    xml_set_notation_decl_handler(null, "handler");
} catch (TypeError $e) {
    echo $e->getMessage();
}
?>
xml_set_notation_decl_handler(): Argument #1 ($parser) must be of type XMLParser, null given

Также, начиная с PHP 8.0, ресурс парсера заменен на объект XMLParser.

Расширенные примеры
Сбор всех нотаций в массив
Пример php
<?php
$notations = [];
$parser = xml_parser_create();
xml_set_notation_decl_handler($parser, function($parser, $name, $base, $sys, $pub) use (&$notations) {
    $notations[] = [
        'name' => $name,
        'base' => $base,
        'system' => $sys,
        'public' => $pub
    ];
});

$xml = '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
    <!NOTATION gif SYSTEM "image/gif">
    <!NOTATION jpeg PUBLIC "-//ISO//NOTATION JPEG//EN" "image/jpeg">
    <!NOTATION example PUBLIC "//Example//NOTATION Test//EN" "http://example.com/test">
]>
<root>Тест</root>';

xml_parse($parser, $xml, true);
print_r($notations);
xml_parser_free($parser);
?>
Array
(
    [0] => Array
        (
            [name] => gif
            [base] => 
            [system] => image/gif
            [public] => 
        )
    [1] => Array
        (
            [name] => jpeg
            [base] => 
            [system] => image/jpeg
            [public] => -//ISO//NOTATION JPEG//EN
        )
    [2] => Array
        (
            [name] => example
            [base] => 
            [system] => http://example.com/test
            [public] => //Example//NOTATION Test//EN
        )
)
Парсинг с базовым URI
Пример php
<?php
$parser = xml_parser_create();
xml_set_notation_decl_handler($parser, function($parser, $name, $base, $sys, $pub) {
    echo "База: $base, Системный идентификатор: $sys\n";
});

// Имитация базового URI через xml_parser_set_option
xml_parser_set_option($parser, XML_OPTION_BASE, "http://example.com/dtd/");

$xml = '<?xml version="1.0"?>
<!DOCTYPE doc SYSTEM "test.dtd" [
    <!NOTATION mynote SYSTEM "notation.txt">
]>
<doc/>';

xml_parse($parser, $xml, true);
xml_parser_free($parser);
?>
База: http://example.com/dtd/, Системный идентификатор: notation.txt
Игнорирование дубликатов нотаций
Пример php
<?php
$parser = xml_parser_create();
$seen = [];
xml_set_notation_decl_handler($parser, function($parser, $name, $base, $sys, $pub) use (&$seen) {
    if (isset($seen[$name])) {
        echo "Пропуск дубликата нотации: $name\n";
        return;
    }
    $seen[$name] = true;
    echo "Уникальная нотация: $name\n";
});

$xml = '<!DOCTYPE doc [
    <!NOTATION a SYSTEM "">
    <!NOTATION b SYSTEM "">
    <!NOTATION a SYSTEM "">
]>
<doc/>';

xml_parse($parser, $xml, true);
xml_parser_free($parser);
?>
Уникальная нотация: a
Уникальная нотация: b
Пропуск дубликата нотации: a

PHP xml_set_notation_decl_handler function comments

En
Xml set notation decl handler Set up notation declaration handler