在 EXPLICIT 模式中,查询书写器控制由执行查询所返回的 XML 文档的形式。必须以特定的方
式编写查询,将有关预期嵌套的附加信息显式指定为查询的一部分。可用 directive 在列级指定附
加的配置。当指定EXPLICIT 模式时,必须负责确保生成的 XML 符合语法规则并且有效(对于
XML-DATA 架构)。
1、处理 EXPLICIT 模式查询和通用表 EXPLICIT 模式将查询执行所得到的行集转换为 XML 文档。为使 EXPLICIT 模式生成 XML 文
档,行集必须具有特定的格式。这需要以某种方式编写 SELECT 查询以生成具有特定格式的行集(
称为通用表),可对该行集进行处理以生成请求的 XML 文档。
EXPLICIT 模式首先要求查询生成两个元数据列:
(1) 在 SELECT 子句中指定的第一列必须是命名 (Tag) 标记号。Tag 列存储当前元素的标记
号。Tag 是整型数据类型。
(2) 指定的第二列必须是父元素的命名 (Parent) 标记号。Parent 列存储父元素的标记号。
这些列用于确定 XML 树中的父子层次结构。这些信息随后用于生成预期的 XML 树。如果存储在
Parent 列中的父标记值是 0 或 NULL,则将行放置在 XML 层次结构的顶层。
通用表的其余部分充分描述所得到的 XML 文档。行集(通用表)中的数据垂直分区成组。每组
成为结果中的一个 XML 元素。
FOR XML EXPLICIT 模式要求 SELECT 查询以某种方式指定通用表中的列名。它要求
SELECT 查询将元素名与标记号相关联,并提供通用表列名中的特性名(默认情况下是特性名)。此
外,若要得到与父实例相关联的正确子实例,需要对行集排序,使子实例紧跟在它的父实例后。简言
之,通用表的列名、Tag 和 Parent 元列中的值以及通用表格式的数据所提供的信息都用于生成所期
望的 EXPLICIT 模式的 XML 文档。
SELECT 查询还必须指定通用表中的列名。通用表中的列名使用 XML 类属标识符和特性名进行编
码。通用表列名中的元素名、特性名和其它转换信息的编码被指定为:
ElementName!TagNumber!AttributeName!Directive
参数 ElementName
是所得到的元素类属标识符(例如,如果将 Customers 指定为 ElementName,则
<Customers> 是元素标记)。
TagNumber
是元素的标记号。借助于通用表中的两个元数据列(Tag 和 Parent),TagNumber
用于表示 XML 树中的 XML元素嵌套。每个 TagNumber 都准确对应于一个 ElementName。
AttributeName
是 XML 特性的名称(如果没有指定 Directive)或包含的元素名(如果 Directive 是
xml、cdata 或 element)。 如果指定 Directive,则 AttributeName 可以为空。这种情况下,列中包含的值直接
由具有指定 ElementName 的元素所包含。
Directive
是可选命令。如果没有指定 Directive,则必须指定 AttributeName。如果没有指定
AttributeName 且没有指定 Directive(如 Customer!1),则表示元素命令(如
Customer!1!!element)且包含数据。
Directive 有两种用途。该选项用于分别使用关键字 ID、IDREF 和 IDREFS 对 ID、
IDREF 和 IDREFS 进行编码。还用于表示如何使用关键字 hide、element、xml、xmltext
和 cdata 将字符串数据映射到 XML。大多数情况下允许在这些组中组合指令,但是不能
在组本身中进行组合。
ID 可将元素特性指定为 ID 类型的特性。然后可以使用 IDREF 和 IDREFS 特性引用它们,
以启用文档内的链接。但是,如果没有请求 XMLDATA,则此关键字无效。
IDREF 指定为 IDREF 的特性可用于引用 ID 类型的特性,以启用文档内的链接。但是,如果没有
请求 XMLDATA,则此关键字无效。
IDREFS 指定为 IDREFS 的特性可用于引用 ID 类型的特性,以启用文档内的链接。但是,如果没
有请求 XMLDATA,则此关键字无效。
hide 不显示特性。这对于按照不出现在结果中的特性对结果进行排序可能很有用。
element 不生成特性。而是生成具有指定名称的包含元素(如果没有指定特性名则直接生成包含元素)。
包含数据被编码为实体(例如,字符 < 变成 <)。该关键字可以与 ID、IDREF 或
IDREFS 组合。
xml 除了不进行实体编码外,该命令与元素命令相同(例如,字符 < 仍是 <)。除了 hide 外,
该命令不能与任何其它命令一起使用。
xmltext 列内容应包在单个标记内,以便与文档的其它部分集成。在提取 OPENXML 存储在列中的
溢出(未用完的)XML 数据时该命令很有用。有关更多信息,请参见使用 OPENXML 编写
XML。 如果指定了 AttributeName,则标记名由指定名称替换; 否则通过将内容放在容器的起始处而不进行实体编码,将特性追加到包含元素的当前特性列表。
含有该命令的列必须是文本类型(varchar、nvarchar、char、nchar、text、ntext)。
该命令只能与 hide 一起使用。在提取存储在列中的溢出数据时该命令很有用。
如果内容不是有效的 XML,则该行为不明确。
cdata 通过用 CDATA 节环绕数据来包含数据。不对内容进行实体编码。原始数据类型必须是文本
类型(varchar、nvarchar、text、ntext)。该命令只能与 hide 一起使用。当使用该命
令时,不应指定 AttributeName。
2、示例
示例 A 和 B 详细说明了编写使用 EXPLICIT 模式的查询的过程。该过程适用于后面的其它示例。
A. 检索客户和订单信息 下例检索客户和订单信息。假定希望生成下面的层次结构:
<Customer CustomerID="ALFKI">
<Order OrderID=10643> <Order OrderID=10692>
...
</Customer> <Customer CustomerID="ANATR" >
<Order OrderID=10308 > <Order OrderID=10625 >
...
</Customer>
生成所得到的 XML 树的查询生成通用表,该表包含两个元数据列:Tag 和 Parent。因此,在
指定查询时 SELECT 子句必须指定这两列。这两列中的值用于生成 XML 层次结构。
<Customer> 元素位于顶层。在下面的示例中,指派给此元素的 Tag 值为 1(该值可以是任
何数字,但是有唯一的数字与每个元素名相关联)。因为 <Customer> 是顶层元素,所以其
Parent 标记值为 NULL。
<Order> 元素是 <Customer> 元素的子元素。因此,<Order> 元素的 Parent 标记值为 1
(将 <Customer> 标识为其父元素)。指派给 <Order> 元素的 Tag 值为 2。
可使用两个 SELECT 语句编写查询并使用 UNION ALL 组合这两个语句的结果:
在第一个 SELECT 语句中,获取所有 <Customer> 元素及其特性值。在含有多个 SELECT
语句的查询中,只使用在第一个查询中指定的列名(通用表列名)。忽略在第二个 SELECT 语句中
指定的列名。因此,指定 XML 元素和特性名的通用表的列名包含在下面的查询中:
SELECT 1 as Tag, NULL as Parent, Customers.CustomerID as [Customer!1!CustomerID], NULL as [Order!2!OrderID] FROM Customers
在第二个查询中检索所有 <Order> 元素及其特性值:
SELECT 2, 1, Customers.CustomerID, Orders.OrderID FROM Customers, Orders WHERE Customers.CustomerID = Orders.CustomerID
使用 UNION ALL 组合此查询中的两个 SELECT 语句。
以只进方式对通用表行集(包含所有数据和元数据)逐行扫描,以生成所得到的 XML 树。为了
输出正确的 XML 文档层次结构,指定通用表中的行顺序也很重要。为此可在查询中使用 ORDER BY
子句。
下面是最终查询:
SELECT 1 as Tag, NULL as Parent, Customers.CustomerID as [Customer!1!CustomerID], NULL as [Order!2!OrderID] FROM Customers
UNION ALL SELECT 2, 1, Customers.CustomerID, Orders.OrderID FROM Customers, Orders WHERE Customers.CustomerID = Orders.CustomerID ORDER BY [Customer!1!CustomerID], [Order!2!OrderID] FOR XML EXPLICIT
所得到的通用表是有四列的表。为了举例说明,只显示几行。
Tag Parent Customer!1!CustomerID Order!2!OrderID 1 NULL ALFKI NULL 2 1 ALFKI 10643 2 1 ALFKI 10692 2 1 ALFKI 10702 2 1 ALFKI 11011 2 1 ALFKI ... 1 NULL ANATR NULL 2 1 ANATR 10308 2 1 ANATR 10625 2 1 ANATR ...
下面描述处理通用表中的行以生成所得到的 XML 树:
第一行标识 Tag 值 1。标识所有含有 Tag 值 1 的列。只有一列含有 Tag 值 1:
Customer!1!CustomerID。此列名由元素名 (Customer)、标记号 (1) 和特性名 (CustomerID)
组成。因此,创建 <Customer> 元素并向其添加特性 CustomerID。然后将该列值指派为该特性值。
第二行有 Tag 值 2。因此,标识所有含有 Tag 值 2 的列。只有一列含有 Tag 值 2:
Order!2!OrderID。此列名由元素名 (Order)、标记号 (2) 和特性名 (OrderID) 组成。该行也将
<Customer> 标识为其父元素(Parent 值为 1)。结果,创建 <Order> 元素作为 <Customer>
元素的子元素并向其添加特性 OrderID。然后将该列值指派为该特性值。
以相同的方式处理后面含有 Tag 值 2 的所有行。
标识含有 Tag 值 1 的某行。标识含有 Tag 值 1 的 Customer!1!CustomerID 列。该列标识
没有父元素(Parent 为 NULL)的 <Customer> 元素。因而,关闭前面的 <Order> 标记和
<Customer> 标记。打开新的 <Customer> 标记并重复此过程。 因为没有在查询中指定 Directive,所以特性名是 XML 特性的名称。下面是部分结果集:
<Customer CustomerID="ALFKI"> <Order OrderID="10643" /> <Order OrderID="10692" /> <Order OrderID="10702" /> <Order OrderID="11011" /> </Customer> <Customer CustomerID="ANATR"> <Order OrderID="10308" /> <Order OrderID="10625" /> </Customer>
B. 指定元素命令
下例检索客户和订单信息。假定希望生成下面的层次结构:(注意 <OrderID> 是 <Order> 的子元素
而不是特性):
<Customer CustomerID="ALFKI"> <Order OrderDate="1997-08-25T00:00:00"> <OrderID>10643</OrderID> </Order> <Order OrderDate="1997-10-03T00:00:00"> <OrderID>10692</OrderID> </Order> ... </Customer>
<Customer> 元素位于顶层。在下例中,为 <Customer> 指派 Tag 值 1。因为 <Customer> 为顶
层元素,所以其Parent 标记值为 NULL。
<Order> 元素是 <Customer> 元素的子元素。因此,<Order> 元素的 Parent 标记值为 1(将
<Customer> 标识为其父元素),并为其指派 Tag 值 2。
<Order> 元素具有作为包含元素(不是特性)的 <OrderID>。因此,在检索该值时,必须指定 element
命令。可使用两个 SELECT 语句编写查询,并使用 UNION ALL 组合这两个语句的结果:
在第一个 SELECT 语句中,获取所有 <Customer> 元素及其特性值。在含有多个 SELECT 语句的查
询中,只使用在第一个查询中指定的列名(通用表列名)。忽略在第二个 SELECT 语句中指定的列名。因此,
指定 XML 元素和特性名的通用表的列名包含在下面的查询中:
SELECT 1 as Tag, NULL as Parent, Customers.CustomerID as [Customer!1!CustomerID], NULL as [Order!2!OrderID!element], NULL as [Order!2!OrderDate] FROM Customers
在第二个查询中检索所有 <Order> 元素及其特性值。因为需要使用 ORDER BY 子句对含有子元素的父
元素进行分组,所以该查询选择 Customers.CustomerID。
SELECT 2, 1, Customers.CustomerID, Orders.OrderID, Orders.OrderDate FROM Customers, Orders WHERE Customers.CustomerID = Orders.CustomerID
使用 UNION ALL 组合此查询中的两个 SELECT 语句。
使用 ORDER BY 子句指定所生成的通用表行集中的行顺序。
下面是最终查询:
SELECT 1 as Tag, NULL as Parent, Customers.CustomerID as [Customer!1!CustomerID], NULL as [Order!2!OrderID!element], NULL as [Order!2!OrderDate] FROM Customers
UNION ALL SELECT 2, 1, Customers.CustomerID, Orders.OrderID, Orders.OrderDate FROM Customers, Orders WHERE Customers.CustomerID = Orders.CustomerID ORDER BY [Customer!1!CustomerID], [Order!2!OrderID!element] FOR XML EXPLICIT
所得到的通用表是有五列的表。为了举例说明,只显示几行。
Tag Parent Customer!1!CustomerID Order!2!OrderID!element Order!2!OrderDate 1 NULL ALFKI NULL NULL 2 1 ALFKI 10692 1997-10-03T00:00:00 2 1 ALFKI 10702 1997-10-13T00:00:00 2 1 ALFKI 10835 1998-01-15T00:00:00 ... ... ... ... ... 1 NULL ANATR 10308 1996-09-18T00:00:00 1 NULL ANATR ... ...
下面描述对行集中的行进行处理以生成所得到的 XML 树:
第一行标识 Tag 值 1。因此,标识所有含有 Tag 值 1 的列。只有一列含有 Tag 值 1:
Customer!1!CustomerID列。此列名由元素名 (Customer)、标记号 (1) 和特性名 (CustomerID)
组成。因此,创建 <Customer> 元素并向其添加特性 CustomerID。然后将该列值指派为该特性值。
第二行含有 Tag 值 2。标识含有 Tag 值 2 的所有列。有两列含有 tag号 2:
Order!2!OrderID!element 和 Order!2!OrderDate。 列名 Order!2!OrderDate 由元素名
(Order)、标记号 (2) 和特性名 (OrderDate) 组成。该行将 <Customer>标识为其父元素(Parent
值为 1)。因此,创建 <Order> 元素作为 <Customer> 元素的子元素并向其添加特性 OrderID。将
该列值指派为该特性值。列名 Order!2!OrderID!element 由命令 (element) 组成。因此,生成一个
包含元素 (<OrderID>)。将该列值指派为该元素值。
以相同的方式处理后面含有 Tag 值 2 的所有行。
标识含有 Tag 值 1 的某行。标识含有 Tag 值 1 的 Customer!1!CustomerID 列。该列标识
没有父元素(Parent 为 NULL)的 <Customer> 元素。因而,关闭前面的 <Order> 标记和
<Customer> 标记。打开新的 <Customer> 标记并重复此过程。
说明: 在此查询中,如果更改列名 (Order!2!OrderID!element) 以便不指定特性名
(Order!2!!element),则该查询直接生成包含元素。
C. 指定 element 命令和实体编码
如果将 directive 设置为 element,则对包含数据进行实体编码。例如,如果在 Customers 表中
有一位客户联系人的姓名是 Mar<ia Anders,则下面的查询将对所包含的数据进行编码:
--Update customer record. UPDATE Customers SET ContactName='Mar<ia Anders' WHERE ContactName='Maria Anders' GO
下面的查询返回客户 ID 和联系人姓名信息。
编写生成通用表的查询的过程和对通用表行集进行处理以生成所得到的 XML 文档的过程,与在示例
A 或示例 B 中描述的过程相似。
SELECT 1 as Tag, NULL as Parent, Customers.CustomerID as [Customer!1!CustomerID], Customers.ContactName as [Customer!1!ContactName!element] FROM Customers ORDER BY [Customer!1!CustomerID] FOR XML EXPLICIT GO -- set the value back to original UPDATE Customers SET ContactName='Maria Anders' WHERE ContactName='Mar<ia Anders' GO
下面显示部分结果。因为在查询中指定了 element 命令,所以指定的特性名是包含元素的名称。也
对 ContactName 进行实体编码(将 ContactName 中的 < 字符返回为 <)
<Customer CustomerID="ALFKI"> <ContactName>Mar<ia Anders</ContactName> </Customer> <Customer CustomerID="ANATR"> <ContactName>Ana Trujillo</ContactName> </Customer> |