else if (empty($e/_)then $d
else data($e)
}
С помощь этой функции запрос Q5 можно переписать (здесь отсутствующие или пустые элементы commission и bonus считаются равными нулю).
for $e in $emps
return
<emp>
{
$e/name,
<pay> | {$e/salary
+ defaulted ($e/commission,0)
+ defaulted ($e/bonus,0)}
</pay>
}
</emp>
sortby(pay)
Функция, в теле которой присутствует вызов самой себя, называется рекурсивной (recursive), и две функции, в теле каждой из которых присутствует вызов другой функции пары, называются взаимно рекурсивными (mutually recursive). В следующем примере рекурсивная функция depth может быть вызвана для элемента и возвращает глубину элемента в иерархии, начинающейся с аргумента вызова. Если у элемент-аргумента отсутствуют потомки, глубина иерархии равна единице. Иначе глубина иерархии на единицу больше максимального значения глубины всех иерархий, корнем которых является потомок элемента-аргумента. Это значение вычисляется путем рекурсивного вызова функции depth.
define function depth(element $e)
returns integer
{
if (empty($e/*)) then 1
else 1 + max
(for $c in $e/* return depth($c))
}
depth(document("bids.xml"))
При создании запроса иногда необходимо сослаться на некоторый тип. Например, как уже было отмечено, при определении функции требуется описать типы параметров функции и ее результата. В других видах выражений XQuery также требуется возможность ссылаться на некоторые типы.
Один из способов сослаться на тип — это указать его квалифицированное имя, или QName. QName может указывать на встроенный тип, такой как xs:integer, или на тип, который определен в некоторой схеме, такой как abc:address. Если в QName имеется префикс пространства имен (часть, расположенная слева от двоеточия), этот префикс должен быть привязан к некоторому идентификатору пространства имен. Это связывание достигается путем описываемого в следующем разделе объявления пространства имен в прологе запроса.
Еще один способ сослаться на тип — сделать это с помощью родового ключевого слова, такого как element или attribute. За этим ключевым словом может следовать QName, которое в большей степени ограничивает имя или тип узла.
За ссылкой на тип может следовать один из трех индикаторов присутствия: «*» означает «ноль или больше», «+» означает «один или больше», а «?» означает «ноль или один». Отсутствие индикатора присутствия означает присутствие ровно одного экземпляра указанного типа.
Процесс проверки корректности может выполняться применительно к документу XML или к части документа, например, отдельному элементу.
В запросной модели данных с каждым узлом-элементом ассоциируется аннотация типа. Аннотация типа свидетельствует о том, что данный элемент прошел проверку на соответствие определенному заявленному типу. Элементы, которые не прошли проверку или не соответствуют заявленному типу, получают аннотацию родового типа anyType.
В XQuery запрос состоит из двух частей, называемых прологом запроса (query prolog) и телом запроса (query body). Пролог состоит из серии объявлений, которые определяют среду для обработки тела. Тело запроса — просто выражение, чье значение определяет результат запроса.
Пролог нужен только в том случае, если тело зависит от одного или нескольких пространств имен, схем или функций. Если такая зависимость существует, объекты, от которых зависит тело запроса должны быть объявлены в прологе запроса.
Помимо объявлений пространств имен пролог запроса может содержать одно или несколько объявлений импорта схемы. При объявлении импорта схемы указывается URI схемы, а также может быть указан второй URI, определяющий место, где может быть найден файл схемы. Цель импорта заключается в том, чтобы предоставить процессору запросов определения элементов, атрибутов и типов, которые объявлены в указанной схеме. Процессор запросов может использовать эти определения для проверки вновь сконструированных элементов, для оптимизации и для проведения статического анализа типов в запросе.
Помимо объявлений пространства имен и импорта схем пролог запроса может содержать одно или несколько определений функции. Функции, определенные в прологе запроса, могут использоваться в теле запроса или в телах других функций.
XQuery определяется в терминах модели данных, основанной на неоднородных последовательностях узлов и атомарных значениях. Экземпляр этой модели данных может содержать один или несколько документов или фрагментов документов XML. Запрос состоит из пролога, который устанавливает среду обработки, и выражения, которое генерирует результат запроса.
В настоящее время XQuery определен на уровне предварительных рабочих документов. Обсуждаются функции полнотекстового поиска, сериализация результатов запроса, обработка ошибок и ряд других вопросов. Скорее всего, окончательная спецификация XQuery будет включать в себя несколько уровней соответствия; например, в ней может быть определено, как следует производить статическую проверку типов, но не будет требоваться, чтобы она выполнялась в каждой реализации, соответствующей спецификации.
Подобно тому, как XML применяется в качестве универсального формата обмена информацией в Сети, XQuery призван служить в качестве универсального формата обмена запросами. Если XQuery получит признание в качестве стандартного средства извлечения информации из источников XML-данных, это поможет реализовать потенциал XML.
XPath (XML Path Language) является языком для обращения к частям XML-документа.
XPath был создан чтобы организовать доступ к элементам документа XML из файла стилей XSLT. XPath создан на основе XML и является стандартом консорциума W3C.
В XPath используется компактный синтаксис, отличный от принятого в XML.
В 2007 году завершилась разработка версии 2.0, которая теперь является составной частью языка XQuery.
Здесь стоит остановиться и вспомнить, что XML документ имеет древовидную структуру. В документе имеется всегда один и только один корневой элемент. Инструкция <?xml version="1.0"?> к дереву отношения не имеет. У элементов дерева существуют потомки (или дети) и предки (или родители), у корневого элемента предков нет.
Элементы дерева могут иметь уровни вложенности (далее уровни). У элементов на одном уровне бывают предыдущие и следующие элементы; соответственно, у первого элемента нет предыдущего, а у последнего нет следующего.
<root> - корневой элемент
<node1> - предок - root, следующий на уровне - node2, имеет потомка node11
<node11/> - имеет предка node1
</node1>
<node2/> - предыдущий элемент - node1, следующий - node3, предок - root
<node3/>
</root>
XPath призван помочь обходить всевозможные деревья, вытаскивать необходимые элементы из другой ветви относительно точки обхода, узнавать родителей, детей, атрибуты. Это полноценный язык навигации по дереву.
Для нахождения элемента (-ов) в дереве документа используются пути адресации. Например, рассмотрим такой XML документ:
<html>
<body>
<div>Первый див
<span>спан в первом диве</span>
</div>
<div>Второй див</div>
<div>Третий див
<span class="text">первый спан в третьем диве</span>
<span class="text">второй спан в третьем диве</span>
<span>третий спан в третьем диве</span>
</div>
<img />
</body>
</html>
Рассмотрим также путь адресации /html/body/*/span[@class] (полный синтаксис имеет вид /child::html/child::body/child::*/child::span[attribute::class]), который вернет набор из двух элементов исходного документа (<span class="text">первый спан в третьем диве</span> и <span class="text">второй спан в третьем диве</span>). Путь делится на шаги адресации которые разделяются символом косая черта / . В свою очередь, каждый шаг адресации состоит из трех частей:
- ось (в данном примере child::), это обязательная часть;
- условие проверки узлов (в данном примере это имена элементов документа html, body, span, а символ * означает элемент с любым именем), это обязательная часть;
- предикат (в данном примере attribute::class), необязательная часть заключаемая в квадратные скобки в которой могут содержаться оси, условия проверки, функции, операторы (+, -, <, >) и проч.
Анализ ведется слева направо. Если первый символ это / , то путь адресации считается абсолютным. При этом за узел контекста на первом шаге берется корневой элемент (html). Контекст - это некая точка отсчета, относительно которой расчитывается следующий шаг адресации. Поэтому на каждом шаге адресации мы получаем новый набор узлов документа, и этот набор становится контекстом для следующего шага адресации.
На втором шаге адресации (child::body) контекстом становится html элемент. Ось child:: говорит о том, что необходимо найти все непосредственные потомки элемента html, а условие проверки body говорит о том, что в формируемый набор элементов нужно включить все узлы с именем body. В ходе второго шага адресации получаем набор узлов, состоящий всего из одного элемента body, который и становится элементом контекста для третьего шага.
Третий шаг адресации: child::* . Ось child:: собирает все непосредственные потомки элемента body, а условие проверки * говорит о том, что в формируемый набор нужно включить элементы основного типа с любым именем. В ходе этого шага получаем набор узлов, состоящий из трех элементов div и одного элемента img.
Четвертый шаг адресации: child::span . Теперь контекстом является набор из четырех элементов. И следующий набор узлов создается в четыре прохода (за четыре итерации). При первой итерации узлом контекста становится первый div. Согласно заданной оси child:: и правилу проверки span, в набор включаются непосредственные потомки div-а, имя которых равно span. При второй итерации в набор ничего добавлено не будет, т.к. у второго div нет потомков. Третья итерация добавить в набор сразу три элемента span, а четвертая ничего не добавит, т.к. у элемента img нет потомков. Итак, в ходе проверки получен набор узлов, состоящий из четырех элементов span. Это и будет контекстом для последующей обработки.