В данном режиме можно формировать практически любые документы; структура результирующего XML-документа определяется непосредственно в самом запросе. Запрос может принимать очень сложный вид, ниже будут рассмотрены правила, по которым он составляется.
Первое поле всегда называется tag и представляет собой числовой идентификатор таблицы. Вы можете указывать для него любые числовые значения. В результирующем документе он не появляется, и нужен только, чтобы определить связи между таблицами для формирования иерархического документа. Второе поле называется parent и тоже может представлять любой числовой идентификатор. Он определяет родительскую таблицу для данной таблицы и в результирующем документе также не присутствует. Если родитель отсутствует, указывается 0 или NULL. Для иерархических выборок нужно использовать несколько запросов, объединенных с помощью оператора UNION ALL.
После двух обязательных полей tag и parent следуют поля, которые требуется выбрать из таблицы. Для них должен быть задан псевдоним, определяющий тип XML-узла, его название и другую информацию. Вот синтаксис этого псевдонима:
ElementName!TagNumber!AttributeName!Directive |
Рассмотрим назначение каждой из частей этого псевдонима:
- ElementName – имя элемента, в котором будет находится элемент данного поля. Обычно здесь указывается имя таблицы.
- TagNumber – идентификатор таблицы, в которой находится данное поле. Одному и тому же ElementName всегда должен соответствовать один TagNumber. Он также не отображается ни в каком виде в результирующем документе, однако нужен для определения иерархических связей между таблицами.
- AttributeName – имя атрибута (или элемента), представляющего данное поле.
- Directive – по существу, представляет собой тип узла. Может принимать следующие значения:
element | поле представляется в виде элемента |
xml | То же самое, что element, но не выполняет трансформации текста. Например, символ меньше (<) не превращается в ссылку < |
cdata | значение поля обрамляется соответствующим образом. Имя атрибута указывать совместно с этим ключевым словом нельзя. |
hide | позволяет скрыть поле |
id,idref,idrefs | позволяют делать ссылки на другие элементы. Эти атрибуты имеют значение, только если создается схема данных. |
Рассмотрим небольшой пример. В самом начале мы рассматривали запрос с использованием FOR XML RAW:
select au_fname,au_lname,address from authors where au_fname like 'M%' for xml raw |
Перепишем его с использованием FOR XML EXPLICIT:
select 1 as tag, 0 as parent, au_fname as 'authors!1!fname', au_lname as 'authors!1!lname', address as 'authors!1!address' from authors where au_fname like 'M%' for xml explicit |
Результат будет точно таким же. Немного исправим запрос для демонстрации возможностей директивы FOR XML EXPLICIT.
select 1 as tag, 0 as parent, au_fname as 'authors!1!fname', au_lname as 'authors!1!lname!element', address as 'authors!1!!cdata' from authors where au_fname like 'M%' for xml explicit |
Вот результат:
<authors lname="Green"> <fname>Marjorie</fname> <![CDATA[ 309 63rd St. #411 ]]> </authors><authors lname="O'Leary"> <fname>Michael</fname> <![CDATA[ 22 Cleveland Av. #14 ]]> </authors><authors lname="Smith"> <fname>Meander</fname> <![CDATA[ 10 Mississippi Dr. ]]> </authors><authors lname="Greene"> <fname>Morningstar</fname> <![CDATA[ 22 Graybar House Rd. ]]> </authors><authors lname="DeFrance"> <fname>Michel</fname> <![CDATA[ 3 Balding Pl. ]]> </authors> |
Неплохо для одного запроса! Поскольку для поля au_lname указан атрибут element, оно представлено в виде элемента. Адрес находится в секции CDATA.
Теперь рассмотрим, как формировать иерархические документы. Возьмем такой запрос:
select pub_name,city,fname,lname from publishers as p join employee as e on p.pub_id = e.pub_id where pub_name like 'Binnet%' or pub_name like 'New Moon%' order by pub_name,city,fname,lname |
Он возвращает имена всех служащих издательств Binnet & Hardley и New Moon Books. Результат запроса (20 записей) я приводить не буду, отмечу только, что он содержит большое количество повторяющихся названий издательств, т.к. результат представлен в реляционной форме. Мы же хотим получить следующее:
<pubs PubName="Binnet & Hardley" City="Washington"> <employee First_Name="Anabela" Last_Name="Domingues" /> <employee First_Name="Daniel" Last_Name="Tonini" /> <employee First_Name="Elizabeth" Last_Name="Lincoln" /> <employee First_Name="Helen" Last_Name="Bennett" /> <employee First_Name="Lesley" Last_Name="Brown" /> <employee First_Name="Martine" Last_Name="Rance" /> <employee First_Name="Paolo" Last_Name="Accorti" /> <employee First_Name="Paul" Last_Name="Henriot" /> <employee First_Name="Peter" Last_Name="Franken" /> <employee First_Name="Victoria" Last_Name="Ashworth" /> </pubs><pubs PubName="New Moon Books" City="Boston"> <employee First_Name="Gary" First_Name="Thomas" /> <employee First_Name="Howard" First_Name="Snyder" /> <employee First_Name ="Karin" First_Name="Josephs" /> <employee First_Name ="Laurence" Last_Name="Lebihan" /> <employee First_Name ="Martin" Last_Name="Sommer" /> <employee First_Name ="Mary" Last_Name="Saveley" /> <employee First_Name ="Matti" Last_Name="Karttunen" /> <employee First_Name ="Palle" Last_Name="Ibsen" /> <employee First_Name ="Roland" Last_Name="Mendel" /> <employee First_Name ="Timothy" Last_Name="O'Rourke" /> </pubs> |
И как, спросите вы? Примерно так:
select 1 as tag, -- первый подзапрос 0 as parent, pub_name as 'pubs!1!PubName', city as 'pubs!1!City', NULL as 'employee!2!First_Name', NULL as 'employee!2!Last_Name' from publishers as pubs where pub_name like 'Binnet%' or pub_name like 'New Moon%'union all select 2 as tag, -- второй подзапрос 1 as parent, pubs.pub_name, pubs.city, fname, lname from employee as e, publishers as pubs where (pub_name like 'Binnet%' or pub_name like 'New Moon%') and pubs.pub_id = e.pub_id order by 'pubs!1!PubName', 'pubs!1!City', 'employee!2!First_Name', 'employee!2!Last_Name' for xml explicit |
Давайте рассмотрим все по порядку. Сначала выполняется первый подзапрос. Его результат приведен в таблице 1.
tag | parent | pubs!1!PubName | pubs!1!City | employee!2!First_Name | employee!2!Last_Name |
New Moon Books | Boston | NULL | NULL | ||
Binnet & Hardley | Washington | NULL | NULL |
Таблица 1.
Затем второй (Таблица 2).
tag | parent | pub_name | city | fname | lname |
Binnet & Hardley | Washington | Paolo | Accorti | ||
Binnet & Hardley | Washington | Victoria | Ashworth | ||
Binnet & Hardley | Washington | Helen | Bennett | ||
Binnet & Hardley | Washington | Lesley | Brown | ||
... | ... | ... | ... | ... | ... |
Таблица 2.
Затем происходит сортировка, и на основе полей tag и parent SQL Server формирует иерархический XML документ.
ПРИМЕЧАНИЕ Для отладки подобных запросов лучше не указывать оператор FOR XML EXPLICIT. Тогда данные будут представлены в обычной реляционной форме. |
На этом мы, пожалуй, закончим рассмотрение оператора FOR XML EXPLICIT – приведение примеров использования всех атрибутов заняло бы слишком много места.