С одной стороны, в языке XPath используются знакомые каждому программисту операторы сравнения «равно», «не равно», «меньше», «больше» и другие. С другой стороны, эти операторы умеют работать не только с примитивными типами, но и с целыми наборами узлов. Незнание правил сравнения наборов узлов может привести к некоторым сюрпризам.
Попробуйте быстро ответить на вопрос, чему равно следующее выражение:
Если ваш ответ —
Простая задача: проверить, равен ли атрибут
При решении обратной задачи довольно часто можно увидеть следующий код:
В большинстве случаев этот код работает так, как ожидается. Однако в случае, когда атрибут
Правильное решение задачи:
Что в переводе на русский означает: не существует ни одного атрибута
Возьмём следующий документ:
Применим различные сочетания операторов равенства, неравенства и отрицания:
Как видите, возможна ситуация, когда выражение
При сравнении двух узлов они приводятся к строке. Как быть, если нужно проверить не совпадение строкового представления, а идентичность? Другими словами, необходимо установить, что два проверяемых узла суть один и тот же узел. Такая задача, например, встречается в группировке Мюнха.
Первое решение — на чистом XPath:
В данном выражении используется свойство оператора объединения, заключающееся в том, что один и тот же узел не может войти в результат операции дважды. Если в итоге получен единственный узел, значит, исходные узлы идентичны.
Второе решение использует XSLT-функцию generate-id:
Данная функция по определению возвращает одинаковый результат для одного и того же узла. Если результаты работы функции равны, значит, исходные узлы идентичны.
Комментарии и дополнения приветствуются.
Попробуйте быстро ответить на вопрос, чему равно следующее выражение:
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)
Данная функция по определению возвращает одинаковый результат для одного и того же узла. Если результаты работы функции равны, значит, исходные узлы идентичны.
Комментарии и дополнения приветствуются.