Какой HTML Parser (желательно PHP) поддерживает получение смещения текущего node во входной строке?

Я ищу анализатор HTML или XML, который позволяет получить доступ к смещению/позиции текущего элемента в строке ввода .

Например, если пройти через эту строку:

<div>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit</p>
    <p>sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
</div>

Я ищу способ получить начальную позицию (включая пробелы) каждого тега <p>, здесь: 7 и 72.

Было бы здорово, если бы PHP-парсер поддерживал это изначально (я смотрел DOM, XMLReader и другие библиотеки, упомянутые в этом вопросе SO, но не нашли способ сделать это), но в противном случае любой язык/структура будет в порядке.

Примечание. Связано с этим вопросом, но менее локализовано.

Ответ 1

Возможно, вы могли бы использовать Generic XML parser class (также на github).
Согласно описанию автора:

  • Проводит произвольный ввод XML и строит массив со структурой всех элементов тега и данных.
  • Он может проверять и извлекать данные из целого документа XML всего за один раз. Он поддерживает валидацию общих типов значений тегов и может выполнять выборочные проверки с использованием подкласса.
  • Необязательно, отслеживает позиции каждого элемента, чтобы можно было определить точное местоположение элементов, которые могут быть контекстуально ошибочными.
  • Поддерживает анализируемый кеш файлов, чтобы минимизировать накладные расходы при регулярном анализе одного и того же файла.
  • Оптимизированный синтаксический анализ упрощенных форматов XML (SML), игнорирующих атрибуты тега.
  • Проверять и извлекать данные из целого XML-документа с помощью одного вызова функции

Я тестировал его с помощью этого кода:

<?php

require('xml_parser.php');

$file_name = 'test.xml';
$error = XMLParseFile($parser, $file_name, 1, $file_name.'.cache');

foreach ($parser->structure as $key => $val) {
    if (is_array($val) && isset($val['Tag']) && !strcasecmp($val['Tag'], 'p')) {
        print_r($parser->positions[$key]);
    }
}

?>

Файл test.xml содержит ваш образец HTML-фрагмента.
Запустив script из командной строки, я получаю этот вывод:

Array
(
    [Line] => 2
    [Column] => 7
    [Byte] => 12
)
Array
(
    [Line] => 3
    [Column] => 7
    [Byte] => 80
)

Итак, поле Byte - это, вероятно, то, что вы ищете.
Чтобы лучше понять, как это работает, посмотрите также исходный код.

Ответ 2

Если вы не против кодирования в Java (после Java-кода есть решение в PHP), вы можете использовать метод indexOf в классе String, получив смещение, если этот токен.

Вот пример:

class Index {
    public static void main ( String [] args )
    {   
        String token = "<p>";
        String input = "<p> hola </p> <p> adios </a>";
        int beginIdx = -1; 
        while ( (beginIdx = input.indexOf( token, beginIdx + 1 )) != -1 ) {                                                                                                                                         
            System.out.println( "Token at: " + beginIdx );
        }   
    }   
}

И результат:

Token at: 0
Token at: 14

В PHP есть аналогичная функция:

int strrpos ( string $haystack , string $needle [, int $offset = 0 ] )

Вы можете быстро просмотреть страницу "man" (он содержит несколько примеров): http://php.net/manual/es/function.strrpos.php