Xml get current byte index: примеры (PHP)

Использование xml_get_current_byte_index для работы с XML в PHP
Раздел: XML
xml_get_current_byte_index(resource parser): int|false
Описание функции xml_get_current_byte_index

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

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

Функция принимает один обязательный параметр:

  • parser (resource) - ссылка на XML-парсер, созданный функцией xml_parser_create().

Возвращаемое значение: целое число (int) с текущим смещением в байтах или FALSE в случае ошибки.

Базовые примеры использования
Пример 1: Получение позиции при парсинге
<?php
$xml = '<root><item id="1">Текст</item><item id="2">Другой текст</item></root>';
$parser = xml_parser_create();

// Установка обработчиков
xml_set_element_handler($parser, "startElement", "endElement");

function startElement($parser, $name, $attrs) {
    $position = xml_get_current_byte_index($parser);
    echo "Начало элемента $name на позиции: $position байт\n";
}

function endElement($parser, $name) {
    $position = xml_get_current_byte_index($parser);
    echo "Конец элемента $name на позиции: $position байт\n";
}

xml_parse($parser, $xml);
xml_parser_free($parser);
?>
Начало элемента ROOT на позиции: 0 байт
Начало элемента ITEM на позиции: 6 байт
Конец элемента ITEM на позиции: 36 байт
Начало элемента ITEM на позиции: 36 байт
Конец элемента ITEM на позиции: 71 байт
Конец элемента ROOT на позиции: 78 байт
Пример 2: Использование при обработке ошибок
<?php
$xml = '<root><item>Незакрытый элемент';
$parser = xml_parser_create();

function handleError($parser, $code, $msg) {
    $position = xml_get_current_byte_index($parser);
    echo "Ошибка на позиции $position: $msg\n";
}

xml_set_element_handler($parser, function(){}, function(){});
xml_set_error_handler($parser, 'handleError');

if (!xml_parse($parser, $xml, true)) {
    $position = xml_get_current_byte_index($parser);
    echo "Парсинг завершился с ошибкой на байте: $position\n";
}

xml_parser_free($parser);
?>
Ошибка на позиции 38: Could not find end of Start Tag item line 1
Парсинг завершился с ошибкой на байте: 38
Похожие функции в PHP

Возвращает номер текущей строки в XML-документе. Полезно для точного указания местоположения ошибок в многострочных документах.

Определяет текущую колонку (символ в строке) в XML-данных. Используется вместе с xml_get_current_line_number для детального отчета об ошибках.

XMLReader::expand

Метод класса XMLReader позволяет получить текущий узел как объект DOM. Класс XMLReader предоставляет более современный и эффективный способ последовательного чтения XML.

Функция xml_get_current_byte_index применяется только с устаревшим XML-парсером на основе функций xml_parser_create. Для новых проектов рекомендуется использовать расширения XMLReader или DOMDocument.

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

class MyHandler(xml.sax.ContentHandler):
    def __init__(self):
        self.locator = None
    
    def setDocumentLocator(self, locator):
        self.locator = locator
    
    def startElement(self, name, attrs):
        if self.locator:
            print(f'Позиция: строка {self.locator.getLineNumber()}, ' 
                  f'колонка {self.locator.getColumnNumber()}')

parser = xml.sax.make_parser()
handler = MyHandler()
parser.setContentHandler(handler)
parser.parse('data.xml')
JavaScript: DOMParser

В JavaScript нет прямой аналогии, но позицию можно получить через анализ исходной строки:

const xmlString = '<root><item>test</item></root>';
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(xmlString, "text/xml");
// Позиции байтов не доступны напрямую
MySQL: ExtractValue

Функция для извлечения данных из XML, но без возможности отслеживания позиции:

SELECT ExtractValue('<root><item>test</item></root>', '//item');
test
Типичные ошибки
Передача неверного типа аргумента
<?php
$position = xml_get_current_byte_index('not_a_parser');
var_dump($position);
?>
Warning: xml_get_current_byte_index() expects parameter 1 to be resource, string given
bool(false)
Использование после освобождения парсера
<?php
$parser = xml_parser_create();
xml_parser_free($parser);
$position = xml_get_current_byte_index($parser);
var_dump($position);
?>
Warning: xml_get_current_byte_index(): supplied resource is not a valid XML Parser resource
bool(false)
Некорректная кодировка XML
<?php
$parser = xml_parser_create('UTF-8');
xml_parse($parser, mb_convert_encoding('<тег>значение</тег>', 'Windows-1251'), true);
$position = xml_get_current_byte_index($parser);
echo "Позиция: $position\n";
?>
Позиция: 0 (возможны ошибки парсинга из-за несоответствия кодировок)
Изменения в версиях PHP

Функция xml_get_current_byte_index появилась в PHP 4. Существенных изменений в её работе в последних версиях PHP не было. Однако в PHP 8 были усилены проверки типов аргументов, что привело к более строгим предупреждениям при передаче некорректных значений.

В PHP 8.0 ресурс (resource) парсера был заменен на объект XMLParser, но обратная совместимость сохранена для большинства функций, включая xml_get_current_byte_index.

Расширенные примеры
Мониторинг прогресса парсинга больших файлов
Пример php
<?php
function parse_large_xml($file, $chunk_size = 4096) {
    $parser = xml_parser_create();
    $total_bytes = filesize($file);
    
    xml_set_element_handler($parser, function($p, $name) use ($total_bytes) {
        $current = xml_get_current_byte_index($p);
        $percent = round(($current / $total_bytes) * 100, 2);
        echo "Прогресс: $percent% ($current/$total_bytes байт)\n";
    }, null);
    
    $fp = fopen($file, 'r');
    while ($data = fread($fp, $chunk_size)) {
        if (!xml_parse($parser, $data, feof($fp))) {
            $error_byte = xml_get_current_byte_index($parser);
            echo "Ошибка на байте: $error_byte\n";
            break;
        }
    }
    
    fclose($fp);
    xml_parser_free($parser);
}

parse_large_xml('large_data.xml');
?>
Создание резервной точки для возобновления парсинга
Пример php
<?php
class XmlParserWithCheckpoint {
    private $parser;
    private $last_position = 0;
    
    public function __construct() {
        $this->parser = xml_parser_create();
        xml_set_object($this->parser, $this);
        xml_set_element_handler($this->parser, 'startElement', 'endElement');
    }
    
    public function parse($data, $is_final = false) {
        xml_parse($this->parser, $data, $is_final);
        $this->last_position = xml_get_current_byte_index($this->parser);
    }
    
    public function getLastPosition() {
        return $this->last_position;
    }
    
    private function startElement($parser, $name) {
        // Обработка элемента
    }
    
    private function endElement($parser, $name) {
        // Завершение элемента
    }
}

$xml_data = file_get_contents('data.xml');
$parser = new XmlParserWithCheckpoint();
$parser->parse($xml_data, true);
echo "Последняя обработанная позиция: " . $parser->getLastPosition() . " байт\n";
?>
Сравнение позиций при обработке вложенных элементов
Пример php
<?php
$xml = '<root><a><b>Текст</b></a></root>';
$parser = xml_parser_create();
$positions = [];

xml_set_element_handler($parser, 
    function($p, $name) use (&$positions) {
        $positions[$name]['start'] = xml_get_current_byte_index($p);
    },
    function($p, $name) use (&$positions) {
        $positions[$name]['end'] = xml_get_current_byte_index($p);
    }
);

xml_parse($parser, $xml);
print_r($positions);
?>
Array
(
    [ROOT] => Array
        (
            [start] => 0
            [end] => 42
        )
    [A] => Array
        (
            [start] => 6
            [end] => 36
        )
    [B] => Array
        (
            [start] => 9
            [end] => 30
        )
)

PHP xml_get_current_byte_index function comments

En
Xml get current byte index Get current byte index for an XML parser