Используйте следующее выражение:
/Items/Item[not(State='TEST')]/Name
Разница в том, что State!='TEST'
выбирает те элементы, которые имеют любой элемент State
, строковое значение которого не равно TEST
, а not(State='TEST')
выбирает всеэлементы, не имеющие элемента State
, строковое значение которого равно TEST
(независимо от того, существует State
или нет).Это тонкое, но существенное отличие.
От спецификации :
Если один объект для сравнения является набором узлов, а другой - строкой,тогда сравнение будет истинным в том и только в том случае, если в наборе узлов есть узел, так что результат выполнения сравнения строкового значения узла и другой строки будет истинным.
Кроме того, представьте следующий ввод:
<Items>
<Item>
<Name>Item1</Name>
<State>blah</State>
<State>TEST</State>
</Item>
<Item>
<Name>Item2</Name>
<State>TEST</State>
</Item>
</Items>
Это выражение:
/Items/Item[State!='TEST']/Name
... выберет первый Item
элемент Name
, поскольку он содержит хотя бы один элемент State
, не имеющий значения TEST
.
Однако это выражение:
/Items/Item[not(State='TEST')]/Name
... не выбирает элементы.Эта вторая форма очень часто является тем, что вы хотите.
См. Эту заметку из спецификации :
ПРИМЕЧАНИЕ: Если $x
привязан к набору узлов, тогда $x="foo"
не означает то же самое, что и not($x!="foo")
: первое истинно тогда и только тогда, когда некоторый узел в $x
имеет строковое значение foo
;последнее верно тогда и только тогда, когда все узлы в $x
имеют строковое значение foo
.