Проверка равенства, неравенства, идентичности узлов в XPath

Содержание

С одной стороны, в языке XPath используются знакомые каждому программисту операторы сравнения «равно», «не равно», «меньше», «больше» и другие. С другой стороны, эти операторы умеют работать не только с примитивными типами, но и с целыми наборами узлов. Незнание правил сравнения наборов узлов может привести к некоторым сюрпризам.

Попробуйте быстро ответить на вопрос, чему равно следующее выражение:

foo = 'bar' and foo != 'bar'

Если ваш ответ — false, автор предлагает читать дальше.

Сравнение узла со строкой

Простая задача: проверить, равен ли атрибут foo строке 'bar':

@foo = 'bar'

При решении обратной задачи довольно часто можно увидеть следующий код:

@foo != 'bar'

В большинстве случаев этот код работает так, как ожидается. Однако в случае, когда атрибут foo отсутствует, данное выражение возвращает false. Если внимательно прочесть документацию и перевести @foo != 'bar' на русский язык, получится следующее: существует хотя бы один атрибут foo, который не равен 'bar'. При отсутствии атрибута foo условие не выполняется, отсюда false.

Правильное решение задачи:

not(@foo = 'bar')

Что в переводе на русский означает: не существует ни одного атрибута foo, равного 'bar'.

Сравнение набора узлов со строкой

Возьмём следующий документ:

<list>
    <item>foo</item>
    <item>bar</item>
    <item>baz</item>
</list>

Применим различные сочетания операторов равенства, неравенства и отрицания:

Выражение Перевод Результат
item = 'foo' Есть хотя бы один элемент, равный 'foo'. true
item != 'bar' Есть хотя бы один элемент, не равный 'bar'. true
not(item = 'foo') Нет ни одного элемента, равного 'foo'. false
not(item != 'baz') Все имеющиеся элементы равны 'baz'. false

Как видите, возможна ситуация, когда выражение item = 'foo' and item != 'foo' возвращает true.

Проверка идентичности узлов

При сравнении двух узлов они приводятся к строке. Как быть, если нужно проверить не совпадение строкового представления, а идентичность? Другими словами, необходимо установить, что два проверяемых узла суть один и тот же узел. Такая задача, например, встречается в группировке Мюнха.

Первое решение — на чистом XPath:

count($foo | $bar) = 1

В данном выражении используется свойство оператора объединения, заключающееся в том, что один и тот же узел не может войти в результат операции дважды. Если в итоге получен единственный узел, значит, исходные узлы идентичны.

Второе решение использует XSLT-функцию generate-id:

generate-id($foo) = generate-id($bar)

Данная функция по определению возвращает одинаковый результат для одного и того же узла. Если результаты работы функции равны, значит, исходные узлы идентичны.



22 сентября 2009 г.
Азат Разетдинов
http://habrahabr.ru/post/70181/