Xml set processing instruction handler: примеры (PHP)

Функция xml_set_processing_instruction_handler в PHP: полное руководство
Раздел: XML
xml_set_processing_instruction_handler(resource parser, callable handler): bool
Описание функции xml_set_processing_instruction_handler

Функция xml_set_processing_instruction_handler устанавливает обработчик инструкций обработки (Processing Instructions, PI) для XML-анализатора в PHP. Она используется в процессе парсинга XML-документов, когда требуется перехватить и обработать специальные инструкции, которые начинаются с <? и заканчиваются ?>.

Эта функция применяется при использовании библиотеки XML Parser, основанной на событийной модели. Она полезна для обработки, например, инструкций XML стилей (<?xml-stylesheet ... ?>) или других пользовательских PI.

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

Синтаксис: xml_set_processing_instruction_handler(resource $parser, callable $handler): bool

  • $parser (ресурс) - ссылка на XML-анализатор, созданный функцией xml_parser_create().
  • $handler (callable) - функция обратного вызова, которая будет вызываться при обнаружении инструкции обработки. Функция должна принимать три аргумента:
    1. $parser (ресурс) - ссылка на анализатор.
    2. $target (string) - цель инструкции (например, 'xml-stylesheet').
    3. $data (string) - содержимое инструкции после цели.

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

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

Простейший пример перехвата инструкции обработки.

<?php
function piHandler($parser, $target, $data) {
    echo "Цель: $target, Данные: $data\n";
}

$xml_parser = xml_parser_create();
xml_set_processing_instruction_handler($xml_parser, "piHandler");

$xml = '<?xml-stylesheet type="text/css" href="style.css"?><root>test</root>';
xml_parse($xml_parser, $xml, true);
xml_parser_free($xml_parser);
?>
Цель: xml-stylesheet, Данные: type="text/css" href="style.css"
Пример 2: Пользовательская инструкция

Обработка пользовательской инструкции.

<?php
function customPI($parser, $target, $data) {
    if ($target === 'custom-target') {
        echo "Найдена пользовательская инструкция с данными: $data\n";
    }
}

$parser = xml_parser_create();
xml_set_processing_instruction_handler($parser, "customPI");

$data = '<?custom-target some="value"?><doc/>';
xml_parse($parser, $data, true);
xml_parser_free($parser);
?>
Найдена пользовательская инструкция с данными: some="value"
Похожие функции в PHP

Библиотека XML Parser предоставляет несколько функций для установки обработчиков различных событий:

  • xml_set_element_handler() - устанавливает обработчики для открывающих и закрывающих тегов.
  • xml_set_character_data_handler() - устанавливает обработчик для текстовых данных.
  • xml_set_notation_decl_handler() - устанавливает обработчик для объявлений нотаций.
  • xml_set_default_handler() - устанавливает обработчик по умолчанию для всех данных, для которых не установлен специальный обработчик.

Предпочтение функции xml_set_processing_instruction_handler отдают, когда требуется специфическая обработка именно инструкций обработки. Для парсинга XML в целом чаще используют более современные расширения, такие как DOMDocument или SimpleXML, которые предоставляют объектно-ориентированный интерфейс и не требуют ручного управления обработчиками событий.

Альтернативы в других языках программирования
Python: xml.parsers.expat

Модуль expat в Python предоставляет аналогичный событийный подход. Обработчик инструкций обработки задается через атрибут ProcessingInstructionHandler.

import xml.parsers.expat

def pi_handler(target, data):
    print(f"PI: target={target}, data={data}")

parser = xml.parsers.expat.ParserCreate()
parser.ProcessingInstructionHandler = pi_handler

xml_data = b'<?xml-stylesheet href="style.css"?><root/>'
parser.Parse(xml_data, True)
PI: target=xml-stylesheet, data=href="style.css"
JavaScript (Node.js): sax.js

В экосистеме Node.js библиотека sax.js реализует событийный парсер XML. Для обработки инструкций используется событие 'processinginstruction'.

const sax = require('sax');
const parser = sax.parser(true);

parser.onprocessinginstruction = function (data) {
    console.log(`PI: ${data.name} - ${data.body}`);
};

parser.write('<?xml-stylesheet type="text/css"?><root/>').close();
PI: xml-stylesheet - type="text/css"
Отличия от PHP

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

Типичные ошибки
Ошибка 1: Передача несуществующей функции обратного вызова

Если имя функции обработчика указано неверно, возникает предупреждение.

<?php
$parser = xml_parser_create();
xml_set_processing_instruction_handler($parser, "nonExistentFunction");

$xml = '<?pi?>';
xml_parse($parser, $xml, true); // Вызовет предупреждение
?>
Warning: xml_parse(): Unable to call handler nonExistentFunction() in ...
Ошибка 2: Неправильное количество аргументов в функции-обработчике

Функция-обработчик должна принимать ровно три аргумента.

<?php
function wrongHandler($parser) { // Не хватает $target и $data
    // ...
}

$parser = xml_parser_create();
xml_set_processing_instruction_handler($parser, "wrongHandler");

$xml = '<?pi data?>';
xml_parse($parser, $xml, true); // Может привести к неожиданному поведению
?>
// Результат непредсказуем, могут быть предупреждения
Ошибка 3: Попытка использования после освобождения анализатора

Использование ресурса анализатора после вызова xml_parser_free() приводит к ошибке.

<?php
$parser = xml_parser_create();
xml_parser_free($parser);
xml_set_processing_instruction_handler($parser, "someHandler"); // Ошибка
?>
Warning: xml_set_processing_instruction_handler(): supplied argument is not a valid XML Parser resource in ...
Изменения в последних версиях PHP

В PHP 8.0 произошло изменение в типизации аргументов функции. Параметр $handler теперь имеет тип callable, и передача несовместимого значения вызывает ошибку TypeError. Ранее в случае передачи неверного типа могло генерироваться предупреждение.

Кроме того, начиная с PHP 8.0, ресурс XML Parser является объектом типа XMLParser, а не ресурсом (resource). Функции семейства xml_* продолжают работать, но тип аргумента $parser теперь объявлен как XMLParser.

Других значимых изменений в поведении функции xml_set_processing_instruction_handler в последних версиях PHP не было. Основная функциональность остается стабильной.

Расширенные примеры использования
Пример 1: Динамическая обработка разных целей

Обработчик, который по-разному обрабатывает инструкции в зависимости от цели.

Пример php
<?php
function advancedPIHandler($parser, $target, $data) {
    switch (strtolower($target)) {
        case 'xml-stylesheet':
            parse_str(str_replace(' ', '&', $data), $attrs);
            echo "Подключение стиля: {$attrs['href']} (тип: {$attrs['type']})\n";
            break;
        case 'php':
            // Имитация обработки PHP-кода (не выполняется)
            echo "Обнаружен PHP-код (не выполняется): $data\n";
            break;
        default:
            echo "Неизвестная инструкция с целью: $target\n";
    }
}

$parser = xml_parser_create();
xml_set_processing_instruction_handler($parser, "advancedPIHandler");

$xml = '<?xml-stylesheet href="theme.css" type="text/css"?>' .
       '<?php echo "Hello"; ?>' .
       '<?custom-instruction?>' .
       '<root/>';

xml_parse($parser, $xml, true);
xml_parser_free($parser);
?>
Подключение стиля: theme.css (тип: text/css)
Обнаружен PHP-код (не выполняется): echo "Hello";
Неизвестная инструкция с целью: custom-instruction
Пример 2: Сбор всех инструкций в массив

Накопление информации об инструкциях обработки для последующего использования.

Пример php
<?php
$collectedPIs = [];

function collector($parser, $target, $data) {
    global $collectedPIs;
    $collectedPIs[] = ['target' => $target, 'data' => $data];
}

$parser = xml_parser_create();
xml_set_processing_instruction_handler($parser, "collector");

$xml = <<<XML
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="transform.xsl"?>
<?custom-pi param="value"?>
<document>
    Content
</document>
XML;

xml_parse($parser, $xml, true);
xml_parser_free($parser);

print_r($collectedPIs);
?>
Array
(
    [0] => Array
        (
            [target] => xml-stylesheet
            [data] => type="text/xsl" href="transform.xsl"
        )

    [1] => Array
        (
            [target] => custom-pi
            [data] => param="value"
        )

)
Пример 3: Комбинирование с другими обработчиками

Использование нескольких обработчиков событий для комплексного парсинга XML.

Пример php
<?php
function startElement($parser, $name, $attrs) {
    echo "Открыт тег: $name\n";
}

function endElement($parser, $name) {
    echo "Закрыт тег: $name\n";
}

function piHandler($parser, $target, $data) {
    echo "[PI] $target: $data\n";
}

$parser = xml_parser_create();
xml_set_element_handler($parser, "startElement", "endElement");
xml_set_processing_instruction_handler($parser, "piHandler");

$xml = '<?target data?><root><child>text</child></root>';
xml_parse($parser, $xml, true);
xml_parser_free($parser);
?>
[PI] target: data
Открыт тег: ROOT
Открыт тег: CHILD
Закрыт тег: CHILD
Закрыт тег: ROOT

PHP xml_set_processing_instruction_handler function comments

En
Xml set processing instruction handler Set up processing instruction (PI) handler