Типы
При создании запроса иногда необходимо сослаться на некоторый тип. Например, как уже было отмечено, при определении функции требуется описать типы параметров функции и ее результата. В других видах выражений XQuery также требуется возможность ссылаться на некоторые типы.
Один из способов сослаться на тип - это указать его квалифицированное имя, или QName. QName может указывать на встроенный тип, такой как xs:integer, или на тип, который определен в некоторой схеме, такой как abc:address. Если в QName имеется префикс пространства имен (часть, расположенная слева от двоеточия), этот префикс должен быть привязан к некоторому идентификатору пространства имен. Это связывание достигается путем описываемого в следующем разделе объявления пространства имен в прологе запроса.
Еще один способ сослаться на тип - сделать это с помощью родового ключевого слова, такого как element или attribute. За этим ключевым словом может следовать QName, которое в большей степени ограничивает имя или тип узла. Например, element обозначает любой элемент, element shipto - любой элемент с именем shipto; и element of type abc:address означает элемент, тип которого - address, объявленный в пространстве имен abc. Ключевое слово attribute обозначает любой атрибут, node - любой узел, а item - любой объект (узел или атомарное значение).
В XQuery также предусмотрен дополнительный синтаксис, который позволяет ссылаться на другие виды узлов и на типы элементов, которые определены в локальной части схемы. Например, element city in customer/address указывает на элемент с именем city, как это определено в контексте схемы customer/address.
За ссылкой на тип может следовать один из трех индикаторов присутствия: означает , означает , а означает . Отсутствие индикатора присутствия означает присутствие ровно одного экземпляра указанного типа. Проиллюстрируем использование индикаторов присутствия.
element memo? | означает возможное появление элемента с именем memo |
element of type order+ | означает один или несколько элементов с типом order |
element* | означает любое число любых элементов |
attribute? | означает необязательный атрибут с любым именем и типом |
Ссылки на тип появляются не только в определениях функции, но и других местах. Одно из таких мест - второй операнд операции instance of, которая возвращает true, если ее первый операнд является экземпляром типа, указанного во втором операнде. Следующие примеры иллюстрируют использование операции instance of (предполагается, что префикс xs привязан к пространству имен схемы ).
49 instance of xs:integer | возвращает true |
"Hello" instance of xs:integer | возвращает false |
<partno>369</partno> instance of element* | возвращает true |
$a instance of element shipto | возвращает true, если $a привязана к элементу с именем shipto |
Проиллюстрируем использование typeswitch. Это выражение может появиться в цикле, где переменная $customer итерируется над множеством элементов customer, каждый из которых имеет подэлемент с именем billing-address. Подэлементы billing-address могут относиться к нескольким различным типам, каждый из которых требуется обрабатывать особым образом. Переменная $a связывается с billing-address, а затем вычисляется одно из нескольких выражений, в зависимости от динамического типа $a. В каждом операторе case $a имеет особый тип, например, в первом условии case типом $a должен быть element of type USAddress.
Если выясняется, что элемент billing-address не соответствует ни одному из ожидаемых типов, результатом выражения является . typeswitch ($customer/billing-address) as $a case element of type USAddress return $a/state case element of type CanadaAddress return $a/province case element of type JapanAddress return $a/prefecture default return "unknown"
Имена типов также используются в трех внешне похожих выражениях XQuery, называемых cast, treat и assert. Каждое из этих выражений содержит ключевое слово, ссылку на тип и выражение, заключенное в скобки.
Выражение cast служит для преобразования результата выражения к одному из встроенных типов XML Schema. Поддерживается предопределенный набор преобразований. Например, результат выражения $x div 5 может быть приведен к типу xs:double с помощью выражения cast as xs:double($x div 5). В случае неудачного выполнения операция приведения типа может вернуть значение ошибки. Например, выполнение cast as xs:integer($mystring) будет успешным, если $mystring - строковое представление integer, но вернет ошибку, если $mystring имеет значение . Выражение cast не может использоваться для приведения значения к типу, определенному пользователем; для этого ему следует написать специальную функцию.
Выражение treat позволяет гарантировать, что динамический (времени исполнения) тип выражения соответствует предполагаемому типу. Например, предположим, что статическим(времени компиляции) типом выражения $customer/shipping-address является Address. Некоторое подвыражение может иметь смысл только для значений, соответствующих подтипу Address, такому как USAddress. Создатель подвыражения может использовать выражение treat для объявления ожидаемого типа подвыражения. treat as USAddress($customer/billing-address)
В отличие от cast, выражение treat на самом деле не меняет тип операнда. Выполнение происходит в два этапа: (1) операнду присваивается некоторый статический тип, который может использоваться для проверки типа при компиляции запроса; (2) во время выполнения, если реальное значение выражения не соответствует указанному типу, возвращается значение ошибки.
Чтобы понять, как процессор запросов мог бы использовать информацию, предоставляемую выражением treat, рассмотрим следующий пример. $customer/billing-address/zipcode
Компилятор XQuery, проверяющий типы, мог бы решить, что в этом примере имеется ошибка типа, поскольку статическим типом $customer/billing-address является Address, а тип Address, в общем случае, не имеет подэлемента zipcode. Однако в следующей формулировке статический тип выражения меняется на USAddress, у которого есть подэлемент zipcode, и ошибка типа исчезает. (treat as USAddress ($customer/billing-address))/zipcode
Как и treat, выражение assert используется для предоставления процессору запросов информации, которая может оказаться полезной для проверки типов. Выражение assert сообщает процессору запросов, что его выражение операнда имеет некоторый статический тип. Если процессор производит статическую проверку типов, он может породить ошибку, если окажется не в состоянии проверить, что данное выражение соответствует заявленному типу. Выражение assert является более строгим, чем выражение treat, поскольку оно относится к статическому типу выражения и, следовательно, не зависит от входных данных и может быть проверено перед выполнением запроса. С другой стороны, выражение treat относится к динамическому типу выражения и, как следствие, зависит от входных данных и может быть проверено только при выполнении запроса.
В следующем примере будет генерироваться ошибка типа времени компиляции, если статическим типом $customer/billing-address является Address. (assert as USAddress ($customer/billing-address))/zipcode
В XQuery не требуется, чтобы в реализации поддерживалась статическая проверка типов. Для процессора запросов, который не обеспечивает статическую проверку, assert эквивалентно treat.