XPath содержит (text (), «некоторая строка») не работает при использовании с узлом с более чем одним текстовым подузлом - PullRequest
220 голосов
/ 07 сентября 2010

У меня небольшая проблема с Xpath содержит dom4j ...

Допустим, мой XML-код

<Home>
    <Addr>
        <Street>ABC</Street>
        <Number>5</Number>
        <Comment>BLAH BLAH BLAH <br/><br/>ABC</Comment>
    </Addr>
</Home>

Допустим, я хочу найти все узлы, имеющие ABC втекст с корневым элементом ...

Так что xpath, который мне нужно было бы написать, был бы

//*[contains(text(),'ABC')]

Однако Dom4j не возвращает это ...Это проблема dom4j или мое понимание того, как работает xpath.так как этот запрос возвращает только уличный элемент, а не элемент Comment.

DOM делает элемент Comment составным элементом с четырьмя тегами два

[Text = 'XYZ'][BR][BR][Text = 'ABC'] 

Я бы предположил, что запрос все еще долженвернуть элемент, так как он должен найти элемент и запустить на нем, но он не ... ...

следующий запрос возвращает элемент, но он возвращает гораздо больше, чем просто элемент, он возвращаеттакже родительские элементы ... что нежелательно для проблемы ...

//*[contains(text(),'ABC')]

Кто-нибудь знает запрос xpath, который будет возвращать только элементы <Street/> и <Comment/>?

Ответы [ 4 ]

611 голосов
/ 07 сентября 2010

Тег <Comment> содержит два текстовых узла и два <br> узла в качестве дочерних элементов.

Ваше выражение xpath было

//*[contains(text(),'ABC')]

Чтобы разобрать,

  1. * - это селектор, который соответствует любому элементу (то есть тегу) - он возвращает набор узлов.
  2. [] - это условие, которое действует на каждый отдельный узел в этом наборе узлов,Он совпадает, если какой-либо из отдельных узлов, с которыми он работает, соответствует условиям внутри скобок.
  3. text() является селектором , который соответствует всем текстовым узлам, которые являются дочерними для узла контекста- возвращает набор узлов.
  4. contains - это функция, которая работает со строкой.Если ему передан набор узлов, набор узлов преобразуется в строку, возвращая строковое значение узла в наборе узлов, который находится первым в порядке документов .Следовательно, он может соответствовать только первому текстовому узлу в вашем элементе <Comment>, а именно BLAH BLAH BLAH.Поскольку это не совпадает, вы не получите <Comment> в ваших результатах.

Вам необходимо изменить это значение на

//*[text()[contains(.,'ABC')]]
  1. *является селектором, который соответствует любому элементу (т. е. тегу) - он возвращает набор узлов.
  2. Внешние [] - это условия, которые действуют на каждый отдельный узел в этом наборе узлов - здесь он работаеткаждый элемент в документе.
  3. text() является селектором , который соответствует всем текстовым узлам, являющимся дочерними элементами контекстного узла - он возвращает набор узлов.
  4. Внутренний [] - это условие, которое действует на каждый узел в этом наборе узлов - здесь каждый отдельный текстовый узел.Каждый отдельный текстовый узел является отправной точкой для любого пути в скобках, и его также можно явно указать как . в скобках.Он совпадает, если какой-либо из отдельных узлов, с которыми он работает, соответствует условиям внутри скобок.
  5. contains - это функция, которая работает со строкой.Здесь передается отдельный текстовый узел (.).Поскольку ему передается второй текстовый узел в теге <Comment> по отдельности, он увидит строку 'ABC' и сможет соответствовать ей.
6 голосов
/ 25 декабря 2016

[contains(text(),'')] возвращает только true или false. Он не возвращает никаких результатов по элементам.

0 голосов
/ 10 июля 2019

XML-документ:

<Home>
    <Addr>
        <Street>ABC</Street>
        <Number>5</Number>
        <Comment>BLAH BLAH BLAH <br/><br/>ABC</Comment>
    </Addr>
</Home>

Выражение XPath:

//*[contains(text(), 'ABC')]

//* соответствует любому элементу-потомку корневого узла .То есть любой элемент, кроме корневого узла.

[...] является предикатом , он фильтрует набор узлов.Он возвращает узлы, для которых ... равно true:

Предикат фильтрует набор узлов [...], чтобы создать новый набор узлов.Для каждого узла в наборе узлов, подлежащем фильтрации, оценивается PredicateExpr [...];если PredicateExpr для данного узла оценивается как true, узел включается в новый набор узлов;в противном случае он не включается.

contains('haystack', 'needle') возвращает true, если haystack содержит needle:

Функция: логическое значениеСодержит (строка, строка)

Функция содержит возвращает истину, если первая строка аргумента содержит вторую строку аргумента, а в противном случае возвращает ложь.

Но contains() принимает строку какего первый параметр.И это пройденные узлы.Чтобы справиться с этим, каждый узел или набор узлов, переданный в качестве первого параметра, преобразуется в строку с помощью функции string():

Аргумент преобразуется в тип string какесли при вызове строковой функции.

string() функция возвращает string-value из первого узла :

Преобразованный набор узловв строку, возвращая строковое значение узла в наборе узлов, который является первым в порядке документа.Если набор узлов пуст, возвращается пустая строка.

string-value узла элемента :

Строковое значениеузла элемента - это объединение строковых значений всех потомков текстового узла узла элемента в порядке документа.

string-value текстового узла :

Строковым значением текстового узла являются символьные данные.

Итак, в основном string-value - это весь текст, содержащийся в узле (объединение всего текста-потомка)узлов).

text() - это тест узла, который соответствует любому текстовому узлу:

Тест текста узла () имеет значение true для любого текстового узла.Например, child :: text () выберет дочерние текстовые узлы узла контекста.

С учетом сказанного, //*[contains(text(), 'ABC')] соответствует любому элементу (кроме корневого узла), первому текстовому узлу.из которых содержит ABC.Так как text() возвращает набор узлов, который содержит все дочерние текстовые узлы узла контекста (относительно которого вычисляется выражение).Но contains() занимает только первое.Таким образом, для документа выше путь соответствует элементу Street.

Следующее выражение //*[text()[contains(., 'ABC')]] соответствует любому элементу (кроме корневого узла), который имеет хотя бы один дочерний текстовый узел, который содержит ABC,. представляет узел контекста.В данном случае это дочерний текстовый узел любого элемента, кроме корневого узла.Таким образом, для документа выше путь соответствует элементам Street и Comment.

Теперь, тогда //*[contains(., 'ABC')] соответствует любому элементу (кроме корневого узла), который содержит ABC (в объединениипотомков текстовых узлов).Для документа выше он соответствует элементам Home, Addr, Street и Comment.Таким образом, //*[contains(., 'BLAH ABC')] соответствует элементам Home, Addr и Comment.

0 голосов
/ 19 октября 2018

Это заняло у меня немного времени, но, наконец, понял. Пользовательский xpath, содержащий текст ниже, отлично работал для меня.

//a[contains(text(),'JB-')]
...