Улучшите XPath-запрос, чтобы правильно различать текстовые узлы - PullRequest
0 голосов
/ 02 сентября 2018

В прошлом я широко использовал 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
  • Мэри: Один Два Три

* 1033 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 Ответ

0 голосов
/ 03 сентября 2018

Вы ожидаете слишком многого от 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
...