Есть ли какой-нибудь лучший XPath для выбора div на основе текста внутри родителя или любого из потомков?
Используйте .
, а не text()
.
//*[contains(., 'Tag 1')]
text()
не дает вам «текст» элемента.
Он дает вам список (!) текстовых узлов , которые являются прямыми дочерними элементами текущего узла контекста. Когда узел контекста равен <div>
в примере # 2, этот список будет состоять из трех текстовых узлов, содержащих только пробелы. Я выделил их скобками:
<div title='Title2'>[
]<input type='checkbox' />[
]<span>Tag 1<span>[
]</div>
'Tag 1'
является ребенком <span>
, а не <div>
.
Теперь contains()
не принимает списки узлов. Если вы дадите ему список узлов, он будет учитывать только строковое значение самого первого узла в этом списке. Строковое значение узла - это объединение всех содержащихся в нем текстовых узлов, а не только прямых дочерних элементов.
.
относится к узлу контекста. В примере №2 это сам <div>
. contains()
снова преобразует его в строку, но на этот раз эта строка на самом деле содержит Tag 1
. Другой способ написать это:
//*[contains(string(.), 'Tag 1')]
Это то, что вы думали text()
сделает.
Теперь //*
является рекурсивным, это означает, что будут выбраны <div>
, <span>
и все <div>
предки, потому что все они содержат Tag 1
в некоторой точке.
Используйте что-то более конкретное, чем //*
, чтобы исправить это.