Улучшение XPath-запроса для правильного различения текстовых узлов

В прошлом я широко использовал XPath. В настоящее время я сталкиваюсь с проблемой, которую не могу решить.

Ограничения

  • чистый XPath 1.0
  • нет вспомогательных функций (например, нет "concat ()")

HTML-разметка

<span class="container">
    Peter: Lorem Impsum
    <i class="divider" role="img" aria-label="|"></i>
    Paul Smith: Foo Bar BAZ
    <i class="divider" role="img" aria-label="|"></i>
    Mary: One Two Three
</span>

Вызов

Я хочу извлечь три последовательных строки:

  • Питер: Лорем Импсум
  • Пол Смит: Foo Bar BAZ
  • Мэри: Раз, Два, Три

XPath

Следующие XPath-запросы - лучшее, что я придумал после ЧАСОВ исследования:

XPath-запрос 1

//span[contains(@class, "container")]

=> Peter: Lorem ImpsumPaul Smith: Foo Bar BAZMary: One Two Three

XPath-запрос 2

//span[contains(@class, "container")]//text()

Peter: Lorem Impsum Paul Smith: Foo Bar BAZ Mary: One Two Three

проблема

Хотя впоследствии можно обработать полученную строку с помощью строковых функций (PHP), я не могу разбить ее на три правильных блока: мне нужен XPath-запрос, который позволяет мне правильно различать текстовые узлы.

Можно ли интегрировать некоторые "искусственные разделители" между текстовыми узлами?

1 ответ

Решение

Вы ожидаете слишком многого от XPath 1.0. XPath 1.0, сам по себе, может помочь вам здесь выбрать

  1. строка или
  2. набор текстовых узлов

Затем вам придется завершить обработку за пределами XPath (как это предлагает Мадс в комментариях).

Чтобы понять ограничения, с которыми вы сталкиваетесь, ваш первый XPath,

//span[contains(@class, "container")]

выбирает набор узлов из span элементы. Среда, в которой работает XPath 1.0, показывает вам (в некоторых вариациях) строковое значение одного такого узла в вашем документе:

Peter: Lorem ImpsumPaul Smith: Foo Bar BAZMary: One Two Three

Но будьте ясны: ваш XPath выбирает набор узлов из span элементы, а не строки здесь.

Ваш второй XPath,

//span[contains(@class, "container")]//text()

выбирает набор узлов из text() узлы. Среда, в которой работает XPath 1.0, показывает строковое значение каждого выбранного text() узел.

Если бы вы могли использовать XPath 2.0, вы могли бы напрямую, внутри XPath, выбрать последовательность строк,

//span[contains(@class, "container")]/text()/string()

или ты можешь присоединиться к ним,

string-join(//span[contains(@class, "container")]/text(), "|")

и прямо получить

Peter: Lorem Impsum
|
Paul Smith: Foo Bar BAZ
|
Mary: One Two Three

или же

string-join(//span[contains(@class, "container")]/text()/normalize-space(), "|")

получить

Peter: Lorem Impsum|Paul Smith: Foo Bar BAZ|Mary: One Two Three
Другие вопросы по тегам