Улучшение 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, сам по себе, может помочь вам здесь выбрать
- строка или
- набор текстовых узлов
Затем вам придется завершить обработку за пределами 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