W3docs

xml_get_current_byte_index()

Функция xml_get_current_byte_index() возвращает текущий байтовый индекс парсера XML в PHP при SAX-разборе документа.

Функция xml_get_current_byte_index() — это встроенная функция PHP, которая возвращает количество байтов XML-документа, уже обработанных парсером. Она входит в состав устаревшего расширения XML Parser, которое разбирает документы в потоковом режиме в стиле SAX: вместо загрузки всего документа в дерево оно вызывает обратные вызовы по мере обхода разметки. Эта функция сообщает где именно находится парсер в момент срабатывания одного из таких обратных вызовов.

Как правило, она вызывается изнутри обработчика, зарегистрированного с помощью xml_set_element_handler() или xml_set_character_data_handler(). Наибольшую пользу она приносит при отображении прогресса разбора большого файла или при определении места в исходном тексте, где появляется конкретный элемент или фрагмент содержимого — например, для формирования сообщения об ошибке с указанием байтового смещения.

На этой странице описаны синтаксис функции, возвращаемое значение, два практических примера и подводные камни, которых следует избегать.

Синтаксис

xml_get_current_byte_index(XMLParser $parser): int

Параметры

  • $parser — дескриптор парсера, возвращённый функцией xml_parser_create() или xml_parser_create_ns(). В PHP 8.0+ это объект XMLParser; в PHP 7.x — resource.

Возвращаемое значение

Возвращает байтовое смещение (целое число, отсчитываемое с нуля) текущей позиции парсера в документе. Поскольку счёт ведётся в байтах, а не в символах, для многобайтового UTF-8 файла индекс будет больше количества символов. Если вам нужен номер строки или столбца, используйте функции-компаньоны xml_get_current_line_number() и xml_get_current_column_number().

Значение имеет смысл только во время выполнения разбора (то есть внутри обработчика). Вызов функции до запуска xml_parse() возвращает 0.

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

Рассмотрим несколько практических примеров использования xml_get_current_byte_index() в PHP.

Пример 1: Получение текущего байтового индекса парсера XML

Предположим, у вас есть XML-файл "data.xml", который нужно разобрать с помощью расширения XML Parser в PHP. Можно использовать функцию xml_get_current_byte_index() внутри SAX-обработчика элементов, чтобы получать текущий байтовый индекс при открытии элемента, вот так:

Получение текущего байтового индекса парсера XML в PHP

$parser = xml_parser_create();
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);

function start_handler($parser, $name, $attrs) {
    $byte_index = xml_get_current_byte_index($parser);
    echo "Element <$name> starts at byte index: $byte_index\n";
}

xml_set_element_handler($parser, "start_handler", null);

$xml_data = file_get_contents("data.xml");
xml_parse($parser, $xml_data, true);
xml_parser_free($parser);

Этот код создаёт XML-парсер с помощью xml_parser_create() и устанавливает опцию, отключающую приведение регистра. Определяется обратный вызов start_handler, который вызывает xml_get_current_byte_index() для получения позиции парсера при открытии каждого элемента. Обработчик регистрируется через xml_set_element_handler(), а xml_parse() выполняет разбор файла. В конце память, занятая парсером, освобождается с помощью xml_parser_free().

Пример 2: Отслеживание прогресса разбора

Предположим, у вас есть большой XML-файл и нужно отображать индикатор прогресса в процессе его разбора. Можно использовать расширение XML Parser с обработчиком символьных данных для отслеживания байтового индекса по мере чтения файла парсером, вот так:

Отслеживание прогресса разбора в PHP

$parser = xml_parser_create();
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);

$total_bytes = filesize("data.xml");
$last_reported = 0;

function progress_handler($parser, $data) {
    global $last_reported, $total_bytes;
    $current = xml_get_current_byte_index($parser);
    if ($current - $last_reported > 1024) { // Report every 1KB
        $progress = round(($current / $total_bytes) * 100);
        echo "Parsing progress: $progress%\n";
        $last_reported = $current;
    }
}

xml_set_character_data_handler($parser, "progress_handler");
xml_parse($parser, file_get_contents("data.xml"), true);
xml_parser_free($parser);

Этот код создаёт XML-парсер и вычисляет общий размер файла. Определяется обратный вызов progress_handler, который сравнивает текущий байтовый индекс с последней зафиксированной позицией. Если прочитано более 1 КБ, функция вычисляет и выводит процент выполнения разбора. Обработчик регистрируется через xml_set_character_data_handler(), а xml_parse() выполняет разбор файла. В конце память, занятая парсером, освобождается с помощью xml_parser_free().

Примечания и подводные камни

  • Байты, а не символы. Для UTF-8 документа с многобайтовыми символами возвращаемое смещение может быть больше позиции в символах. Не воспринимайте его как количество символов.
  • Вызывайте внутри обработчика. Байтовый индекс отражает реальную позицию только во время выполнения обратного вызова. За пределами разбора функция возвращает 0.
  • Смещение может указывать чуть дальше разметки. В зависимости от буферизации libexpat, возвращаемый индекс может соответствовать концу токена, вызвавшего обратный вызов, а не его точному началу. Используйте его для приблизительного отслеживания прогресса и определения позиции, но не для точного побайтового извлечения.
  • Это устаревший SAX API. Для большинства нового кода проще использовать древовидные расширения SimpleXML или DOM. Обращайтесь к расширению XML Parser только тогда, когда вам действительно нужна потоковая обработка очень больших файлов. Смотрите обзор PHP XML parsers для выбора подходящего варианта.

Заключение

В этой статье мы рассмотрели функцию PHP xml_get_current_byte_index() и то, как её можно использовать для получения текущего байтового индекса парсера XML при разборе в SAX-стиле. Мы объяснили, что делает функция, описали её синтаксис и привели примеры практического применения. Следуя этим примерам, вы сможете легко отслеживать позицию парсера и использовать её в своих PHP-приложениях для контроля прогресса или обнаружения конкретных элементов.

Практика

Практика
Что возвращает xml_get_current_byte_index()?
Что возвращает xml_get_current_byte_index()?
Was this page helpful?