Pull to refresh

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

Reading time 2 min
Views 12K
С одной стороны, в языке 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)

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

Комментарии и дополнения приветствуются.
Tags:
Hubs:
+46
Comments 52
Comments Comments 52

Articles