Как создать xpath для выбора элементов, которые не содержат строки - PullRequest
10 голосов
/ 20 апреля 2010

Как использовать что-то похожее на пример ниже, но с противоположным результатом, то есть элементы, которые не содержат (default) в тексте.

<test>
     <item>Some text (default)</item>
     <item>Some more text</item>
     <item>Even more text</item>
</test>

Учитывая это

//test/item[contains(text(), '(default)')]

вернет первый элемент. Есть оператор not, который я могу использовать с содержит?

1 Ответ

18 голосов
/ 20 апреля 2010

Да, есть:

//test/item[not(contains(text(), '(default)'))]

Подсказка: not() - это функция в XPath вместо оператора.


Альтернативный, возможно лучший способ выразить это:

//test/item[not(text()[contains(., '(default)')])]

Между этими двумя выражениями есть небольшое, но важное различие (назовем их A и B соответственно).

Простой случай: Если все <item> имеют только один дочерний текстовый узел, и A, и B ведут себя одинаково.

Сложный регистр: Если <item> может иметь несколько дочерних узлов текстового узла, выражение A соответствует, только если в первом из них встречается '(default)'.

Это потому, что text() соответствует всем дочерним текстовым узлам и создает набор узлов. Пока что нет ничего удивительного. Теперь contains() принимает набор узлов в качестве первого аргумента, но ему нужно преобразовать его в строку, чтобы выполнить свою работу. А преобразование из набора узлов в строку создает только строковое значение первого узла в наборе, все остальные узлы не учитываются (попробуйте string(//item), чтобы понять, что я имею в виду). В простом случае это именно то, что происходит, но результат не так удивителен.

Выражение B решает эту проблему путем явной проверки каждого текстового узла отдельно, а не только проверки строкового значения всего элемента <item>. Поэтому он более устойчивый из двух.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...