У меня небольшая проблема с 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. поскольку этот запрос возвращает только элемент Street, а не элемент Comment.
DOM делает элемент Comment составным элементом с четырьмя тегами два
[Text = 'XYZ'][BR][BR][Text = 'ABC']
Я бы предположил, что запрос все еще должен возвращать элемент, поскольку он должен найти элемент и выполнить на нем содержится, но это не ... ...
следующий запрос возвращает элемент, но он возвращает гораздо больше, чем просто элемент, он также возвращает родительские элементы ... что нежелательно для проблемы ...
//*[contains(text(),'ABC')]
Кто-нибудь знает запрос xpath, который будет возвращать только элементы <Street/>
и <Comment/>
?
//*[contains(text(),'ABC')]
возвращает только<Street>
элемент. Это не возвращает никаких предков<Street>
или<Comment>
.Ответы:
<Comment>
Тег содержит два текстовых узлов и два<br>
узла , как дети.Ваше выражение xpath было
Чтобы сломать это,
*
является селектором, который соответствует любому элементу (то есть тегу) - он возвращает набор узлов.[]
условие, которое действует на каждый отдельный узел в этом наборе узлов. Он соответствует, если какой-либо из отдельных узлов, с которыми он работает, соответствует условиям внутри скобок.text()
является селектором, который соответствует всем текстовым узлам, которые являются дочерними элементами контекстного узла - он возвращает набор узлов.contains
это функция, которая работает со строкой Если передан набор узлов, набор узлов преобразуется в строку, возвращая строковое значение узла в наборе узлов, который находится первым в порядке документов . Следовательно, он может соответствовать только первому текстовому узлу в вашем<Comment>
элементе, а именноBLAH BLAH BLAH
. Так как это не соответствует, вы не получите<Comment>
в ваших результатах.Вы должны изменить это на
*
является селектором, который соответствует любому элементу (то есть тегу) - он возвращает набор узлов.[]
являются условными, которые действуют на каждый отдельный узел в этом наборе узлов - здесь он действует на каждый элемент в документе.text()
это селектором, который соответствует всем текстовым узлам, которые являются дочерними элементами контекстного узла - он возвращает набор узлов.[]
являются условными, которые действуют на каждый узел в этом наборе узлов - здесь каждый отдельный текстовый узел. Каждый отдельный текстовый узел является отправной точкой для любого пути в скобках, и также может быть явно указан как.
внутри скобок. Он соответствует, если какой-либо из отдельных узлов, с которыми он работает, соответствует условиям внутри скобок.contains
это функция, которая работает со строкой Здесь передается отдельный текстовый узел (.
). Поскольку ему передается второй текстовый узел в<Comment>
теге индивидуально, он увидит'ABC'
строку и сможет соответствовать ей.источник
//*[contains(., 'ABC')]
. Я всегда использовал шаблон, предложенный Майком Милкиным, думая, что он более уместен, но просто делатьcontains
то, что мне нужно в текущем контексте, на самом деле кажется тем, чего я хочу чаще.[contains(text(),'')]
возвращает только true или false. Это не вернет никаких результатов элемента.источник
contains(text(),'JB-')
это не работа!conatains
принимает две строки в качестве аргумента -contains(**string**, **string**)
! text () не строка , это функция!XML-документ:
Выражение XPath:
//*
соответствует любому потомок элемента из корневого узла . То есть любой элемент, кроме корневого узла.[...]
является предикатом , он фильтрует набор узлов. Возвращает узлы, для которых...
естьtrue
:contains('haystack', 'needle')
возвращает,true
еслиhaystack
содержитneedle
:Но
contains()
принимает строку в качестве первого параметра. И это пройденные узлы. Чтобы справиться с этим, каждый узел или набор узлов, переданный в качестве первого параметра, преобразуется в строкуstring()
функцией:string()
функция возвращаетstring-value
из первого узла :string-value
из узла элемента :string-value
из текстового узла :Таким образом, в основном
string-value
это весь текст, который содержится в узле (объединение всех дочерних текстовых узлов).text()
это тест узла, который соответствует любому текстовому узлу:Сказав это,
//*[contains(text(), 'ABC')]
соответствует любому элементу (кроме корневого узла), первый текстовый узел которого содержитABC
. Sincetext()
возвращает набор узлов, который содержит все дочерние текстовые узлы узла контекста (относительно которого вычисляется выражение). Ноcontains()
занимает только первое. Таким образом, для документа выше путь соответствуетStreet
элементу.Следующее выражение
//*[text()[contains(., 'ABC')]]
соответствует любому элементу (кроме корневого узла), который имеет хотя бы один дочерний текстовый узел, который содержитABC
..
представляет узел контекста. В данном случае это дочерний текстовый узел любого элемента, кроме корневого узла. Таким образом, для документа выше путь соответствуетStreet
, иComment
элементы.Теперь, тогда,
//*[contains(., 'ABC')]
соответствует любому элементу (кроме корневого узла), который содержитABC
(в конкатенации нисходящих текстовых узлов). Для документа выше , что он соответствуетHome
, сAddr
, вStreet
, иComment
элементы. По существу,//*[contains(., 'BLAH ABC')]
соответствуетHome
, тоAddr
иComment
элементы.источник
Это заняло у меня немного времени, но, наконец, понял. Пользовательский xpath, содержащий текст ниже, работал для меня идеально.
источник
contains(text(),'JB-')
это не работа!conatains
принимает две строки в качестве аргумента -contains(**string**, **string**)
! text () не строка , это функция!Принятый ответ также вернет все родительские узлы. Чтобы получить только фактические узлы с ABC, даже если строка после
:
источник
возвращается
источник