Да, есть:
//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>
. Поэтому он более устойчивый из двух.