(Q5) Задана последовательность элементов emp. Заменить их подэлементы salary, commission и bonus на новый элемент pay, содержащий сумму значений исходных элементов, а результирующую последовательность отсортировать по убыванию значений элемента pay.
for $e in $emps
return
<emp>
{
$e/name,
<pay> {$e/salary + $e/commission+ $e/bonus} </pay>
}
</emp>
sortby (pay)
Иногда желательно определять значение по умолчанию, которое может заменять пропущенные операнды в арифметических выражениях. Ниже объясняется, как в этом случае может использоваться функция, определенная пользователем.
Оператор intersect порождает последовательность, в которую включены все узлы, имеющиеся в обоих операндах. Оператор except позволяет получить последовательность, содержащую все узлы, которые есть в первом операнде, но отсутствуют во втором.
Операторы union, intersect и except возвращают последовательность узлов в порядке документа и удаляют дубликаты из получившихся последовательностей с учетом индивидуальности узлов. Запрос Q6 является примером использования оператора intersect.
(Q6) Создать новый элемент с именем recent-large-bids, содержащий копии всех элементов bid документа bids.xml, которые имеют bid-amount со значением больше 1000 и bid-date со значением позже 1 января 2002 года.
<recent-large-bids>
document("bids.xml")
/*/ bid [bid-amount > 1000.00]
intersect
document("bids.xml")
/*/ bid [bid-date > date("2002-01-01")]
</recent-large-bids>
Выражения, в которых используются операции union, intersect и except, часто можно представить в другом виде. Так, запросу Q6 эквивалентен следующий запрос.
<recent-large-bids>
document("bids.xml")/*/bid
[bid-amount > 1000.00 and bid-date
> date("2002-01-01")]
</recent-large-bids>
Важно помнить о том, что intersect и except бессмысленно использовать для комбинирования узлов разных документов, поскольку узлы в разных документах никогда не могут быть идентичными. Рассмотрим следующий запрос.
document("items.xml")//itemno
except
document("bids.xml")//itemno
В этом запросе операция except применяется к двум последовательностям узлов itemno. Поскольку последовательности узлов выбираются из различных документов, ни один узел во второй последовательности не может быть идентичен узлу из первой последовательности. Результатом запроса будет последовательность всех узлов itemno документа items.xml. Если предполагалось с помощью этого запроса получить список элементов itemno для товаров, которые не имеют ставок, то можно добиться этого воспользовавшись библиотечной функцией empty, которая возвращает true, если ее операнд — пустая последовательность.
for $i in document("items.xml")//item
where empty(document("bids.xml")
//bid [itemno eq $i/itemno])
return $i/itemno
В этом примере предикат itemno eq $i/itemno сравнивает два узла itemno, извлекая и сравнивая их содержимое, а не проверяя их идентичность.
Операция |, оставленная для совместимости с XPath 1.0, эквивалентна операции union. Эти операции иногда применяются в шагах выражения пути. Например, следующее выражение пути находит объединение всех потомков b и потомков c узлов в последовательности, связанной с $a; узлы в этом объединении затем используются в качестве контекстных узлов для следующего шага в пути.
$a/(b | c)/d
Условные выражения обеспечивают возможность выполнения одного из двух выражений в зависимости от значения третьего выражения. Это записывается в знакомом формате if...then...else, поддерживаемом во многих языках. Требуется наличие всех трех условий (if, then и else), а выражение в условии if должно быть заключено в скобки. Результат всего условного выражения зависит от значения выражения в условии if, называемого выражением проверки (test expression). Правила таковы.
Если значением выражения проверки являются булевское значение true или непустая последовательность (используемая как «проверка существования»), то выполняется оператор then.
Если значением выражения проверки являются булевское значение false или пустая последовательность, то выполняется оператор else.
В противном случае условное выражение возвращает значение ошибки.
Следующее простое условное выражение может быть использовано для получения стоимости товара, в зависимости от существования атрибута с именем discounted.
if ($part/@discounted) then $part/wholesale
else $part/retail
Кванторные выражения позволяют проверить некоторое условие, устанавливая, истинно ли оно для некоторого значения последовательности (называется квантором существования) или для всех значений последовательности (называется квантором всеобщности). Результатом всегда является true или false.
Как и FLWR-выражение, кванторное выражение позволяет переменной выполнять итерацию над объектами в последовательности; выполняется поочередное связывание этой переменной с каждым элементом последовательности. Для каждого связывания переменной вычисляется проверочное выражение. Кванторное выражение, которое начинается с some, возвращает значение true, если выражение проверки истинно для некоторого связывания переменной.
some $n in (5,7,9,11)satisfies $n > 10
Кванторное выражение, начинающееся с every, возвращает значение true, если выражение проверки истинно для всех связываний переменной. Например, следующее кванторное выражение возвращает значение false, поскольку выражение проверки истинно не для всех связываний.
every $n in (5,7,9,11)satisfies $n > 10
Использование кванторных выражений иллюстрируется запросом Q7.
(Q7) Найти товары в items.xml, для которых все полученные ставки более чем вдвое превысили начальную цену. Получить копии всех таких элементов item, и поместить их в новый элемент с именем underpriced-items.
<underpriced items>
for $i in document("items.xml")
where every $b in document("bids.xml")
/*/bid [itemno = $i/itemno]
satisfies $b/bid-amount
> 2 * $i/reserve-price
return $i
<underpriced items>
В XQuery предусмотрена библиотека предопределенных функций, а также предоставляется возможность определения пользователями их собственных функций. При вызове аргументы связываются с параметрами функции, и выполняется ее тело, порождая результат вызова функции. Если тип параметра функции не указан, этот параметр может принимать значения любого типа. Если не указан тип результата функции, то функция может возвращать значение любого типа.
В следующем примере определена функция с именем highbid, в качестве параметра использующая узел-элемент и возвращающая десятичное значение. Функция интерпретирует свой параметр как элемент item и извлекает номер товара. Затем она находит и возвращает самую крупную ставку (bid-amount), которая была зафиксирована для товара с этим номером.
define function highbid(element $item)
returns decimal
{
max(document("bids.xml")
//bid [itemno = $item/itemno]/bid-amount)
}
highbid(document("items.xml")
//item [itemno = "1234"])
Типы, используемые при объявлении типов аргументов и результата в определении функции, могут быть простыми, как decimal, или более сложными типами, например, элементами или атрибутами.
В XQuery не поддерживается перегрузка функций, определенных пользователем, т. е. не допускается наличие двух функций с одинаковыми именами. Тем не менее, некоторые встроенные функции являются перегруженными. Например, функция string может преобразовывать в строку аргумент почти любого типа.
Аргументы при вызове функции должны соответствовать объявленным типам параметров функции. С этой целью аргумент функции числового типа может быть приведен к объявленному типу параметра с помощью иерархии приведения integer -> decimal -> float -> double. Аргумент также считается удовлетворяющим условию вызова, если тип этого аргумента является производным типом (т.е. подтипом) объявленного типа параметра. Если функция, ожидающая атомарное значение в качестве параметра, вызывается с аргументом, являющимся элементом, то до передачи аргумента функции из него извлекается типизированное значение элемента и проверяется на совместимость с ожидаемым типом параметра. Значение, производимое телом функции, должно также соответствовать возвращаемому типу, объявленному в определении; используются обычные правила проверки соответствия типов параметров.
Следующий пример иллюстрирует, как пользователь может написать функцию, которая предоставляет значение по умолчанию для отсутствующих данных. Функция с именем defaulted принимает два параметра: узел-элемент (возможно, отсутствующий) и значение по умолчанию. Если элемент присутствует и имеет непустое значение, функция возвращает это значение. Если же элемент отсутствует или пуст, функция возвращает значение по умолчанию.
define function defaulted
(element? $e, anySimpleType $d)
returns anySimpleType
{
if (empty($e))then $d