Язык запросов для XML не был бы самим собой, если бы в нем нельзя было создавать узлы XML-документа. К сожалению, здесь довольно сложно провести аналогию с обычным SQL, потому что в нем вы не имеете возможности получать результирующую выборку в каком-либо виде, отличном от табличного.
Изменение результирующей выборки в XQuery производится при помощи конструкторов узлов. Эти конструкторы предназначены для создания узлов элементов, атрибутов, документов, инструкций обработки, комментариев, пространств имен и текстовых узлов. Кроме этого, есть возможность создавать секции CDATA. В SQL Server-е пока поддерживается создание только узлов элементов, атрибутов, комментариев и текстовых узлов, при чем последние создаются как секции CDATA, что, конечно, является очередным отклонением от стандарта.
Простой конструктор (direct constructor) – это литерал, который создает узел в соответствии с синтаксисом XML. Например, выражение
<a></a> |
является вполне допустимым выражением XQuery, которое конструирует узел элемента а. Подобным же образом можно создавать узлы комментариев, текстовые узлы, узлы инструкций обработки и секции CDATA. Например:
|
|
(: создание секции CDATA:)<![CDATA[Hi from CDATA!]]> (: создание комментария:)<!--Hi from comment!--> (: Создание текстового узла:)"Hi from text!" (: Создание узла инструкции обработки:)<?target Hi from PI!?> |
Что же делать в случае, когда нужно создать атрибут? Ведь нельзя же просто написать:
attr="value" |
На помощь приходят вычисляемые конструкторы.
Вычисляемый конструктор узла – это ключевое слово, обозначающее тип узла, за которым следует название узла (если у данного типа узла может быть название) и значение. Значение узла всегда берется в фигурные скобки, внутри которых можно использовать любое выражение XQuery. Если имя узла должно задаваться динамически, его также можно сделать вычисляемым во время исполнения, путем заключения выражения, вычисляющего имя, в фигурные скобки. Например,
(: Создание атрибута а со значением "b":)attribute a {"b"} (: Создание элемента а со значением "b":)element a {"b"} (: Создание фрагмента семья:)element fam{element husband {attribute income {"180"}, "alex"}, element wife {attribute income {"161"}, "rosa"}, element son {attribute income {"90"}, "dima"}} |
Вот список всех вычисляемых конструкторов. Их точный синтаксис и использование можно найти в [14].
- Конструктор элемента (element).
- Конструктор атрибута (attribute).
- Конструктор документа (document).
- Текстовый конструктор (text).
- Конструктор инструкции обработки (processing-instruction).
- Конструктор узла комментария (comment).
- Конструктор узла пространства имен (namespace).
Какие ограничения имеются в реализации SQL Server? Их много. Например, следующий код:
|
|
declare @xml xmlset @xml = ''select @xml::query('attribute a {"b"}') |
будет выдавать ошибку XQuery: Attribute may not appear outside of an element. По-моему, это сообщение не имеет смысла.
Секция CDATA бесследно исчезает в следующем запросе:
declare @xml xmlset @xml = ''select @xml::query('<![CDATA[Hi from CDATA!]]>')--эквивалентно--declare @xml xml--set @xml = ''--select @xml::query('--"Hi from CDATA"--'</str>) |
результат:
Hi from CDATA!--Должно быть--<![CDATA[Hi from CDATA!]]> |
Не поддерживаются вычисляемые конструкторы документа, комментария, инструкции обработки, текстового узла и пространства имен.
Кроме этого, мне не удалось использовать ни один конструктор узла с вычисляемым именем: SQL Server упорно выдавал ошибку XQuery: Cannot implicitly convert from 'xs:string' to 'xs:QName'.
Атомарные элементы конструируются с помощью литералов и конструкторов. В XQuery определено четыре типа литерала: строковый литерал (все, что заключено в двойные или одинарные кавычки), целочисленный литерал (целое число), вещественный литерал и литерал с плавающей точкой. Например,
целочисленный литерал типа xs:interger | |
10.1 | вещественный литерал типа xs:decimal |
101E-1 | литерал с плавающей точкой типа xs:double |
"string" | строковый литерал типа xs:string |
В выражениях с различными типами операндов выполняется следующее неявное преобразование типов: integer -> decimal -> float -> double.
Если тип операнда после преобразования все же не совместим с типом другого операнда, генерируется ошибка времени компиляции. Тип выражения определяется типом операндов. Например,
1 + 2 | выражение типа xs:integer |
1 + 2.0 | выполняется преобразование литерала 1 до типа xs:double. Тип результата – xs:double |
"1" + 1 | продвижение выполнить нельзя. Ошибка. |
Для конструирования или преобразования типов можно использовать конструкторы атомарных элементов. Конструкторы атомарных элементов – это, по существу, все типы XML Schema. Например,
xs:integer("1") + 1 |
вполне законное выражение, тип которого xs:integer. Здесь выполняется конструирование типа xs:integer из строкового литерала "1".
ПРИМЕЧАНИЕ Для конструкторов элементов и некоторых встроенных функций разрешается перегрузка по типу операндов. Будем надеяться, эта возможность появится и для пользовательских функций. |
Если операнд не может быть преобразован к желаемому типу конструктором, генерируется динамическая ошибка (ошибка времени исполнения).
ПРИМЕЧАНИЕ Это не строгое правило. Если преобразуемое значение задается литералом, процессор может выдать ошибку на этапе компиляции. |
Перегруженные конструкторы атомарных элементов фактически являются выражениями преобразования типов и идентичны использованию оператора cast. Следующие строчки эквивалентны:
xs:integer("1") + 1("1" cast as xs:integer) + 1 |
В XQuery поддерживается также оператор castable, который эквивалентен оператору is в языке VB.NET или в C#. Он возвращает булево значение, равное true, если операнд может быть преобразован к данному типу, и false в противном случае. Например,
if ("1" castable as xs:integer) then "castable"else "not castable" |
Возвращает строку castable.
Оператор castable не поддерживается в текущей версии SQL Server. Возможно, он будет реализован в дальнейшем.