使用 FOR XML EXPLICIT(转)
http://blog.sina.com.cn/s/blog_677b66170100jsve.html
使用 FOR XML EXPLICIT
使用 FOR XML EXPLICIT,您可以控制查询返回的 XML 文档的结构。查询必须用特定的方法编写,让查询结果中指定有关您需要的嵌套的信息。使用 FOR XML EXPLICIT 支持的可选指令,您可以配置各列的处理方式。例如,您可以控制让列显示为元素或显示为属性内容,或者,列只用来给结构排序,而不出现在生成的 XML 中。
有关如何使用 FOR XML EXPLICIT 编写查询的示例,请参见编写 EXPLICIT 模式的查询。
参数
在 EXPLICIT 模式中,SELECT 语句中的前两列必须分别命名为 Tag 和 Parent。Tag 和 Parent 是元数据列,它们的值用来确定查询返回的 XML 文档中元素的父子关系,也就是嵌套。
-
Tag 列 这是在选择列表中指定的第一列。Tag 列存储当前元素的标记值。标记号可以使用的值是 1 到 255。
-
Parent 列 这一列存储当前元素的父级的标记号。如果这一列中的值是 NULL,该行就会被放置在 XML 层次结构的顶层。
例如,有这样一个查询,在没有指定 FOR XML EXPLICIT 时,它会返回下面的结果集。(first_name!1 和id!2 数据列的用途会在下一节给查询添加数据列中介绍)。
Tag | Parent | first_name!1 | id!2 |
---|---|---|---|
1 | NULL | 'Beth' | NULL |
2 | NULL | NULL | '102' |
在这个示例中,Tag 列中的值是结果集中各元素的标记号。两行的 Parent 列都包含 NULL 值。这就是说,两个元素都会在层次结构的顶层生成,在查询包括 FOR XML EXPLICIT 子句时,会给出以下结果:
<first_name>Beth</first_name> <id>102</id>
但是,如果第二行在 Parent 列中的值是 1,结果看起来就会像下面这样:
<first_name>Beth <id>102</id> </first_name>
有关如何使用 FOR XML EXPLICIT 编写查询的示例,请参见编写 EXPLICIT 模式的查询。
给查询添加数据列
除了 Tag 列和 Parent 列以外,查询还必须包含一个或多个数据列。这些数据列的名称控制着在标记过程中解释列的方式。每个列名都拆分为由惊叹号 (!) 分隔的字段。可以为数据列指定以下字段:
ElementName!TagNumber!AttributeName!Directive
ElementName 元素的名称。对于给定的行,会从标记号匹配的第一列的 ElementName 字段中提取为该行生成的元素的名称。如果有多个 TagNumber 相同的列,对于后面的 TagNumber相同的列,会忽略 ElementName。在上面的示例中,第一行会生成一个名为 <first_name> 的元素。
TagNumber 元素的标记号。对于有给定标记值的行,所有在其 TagNumber 字段中具有相同值的列都会向对应该行的元素提供内容。
AttributeName 指定列值是 ElementName 元素的属性。例如,如果数据列具有名称 prod_id!1!color,那么 color 就会显示为 <prod_id> 元素的属性。
Directive 使用这个可选字段,您可以进一步控制 XML 文档的格式。您可以为 Directive 指定以下值中的任何一个:
-
hide 指明此列会为生成结果而被忽略。这条指令可以用于加入只用来给表排序的列。属性名会被忽略,而且不出现在结果中。
有关使用 hide 指令的示例,请参见使用 hide 指令。
-
element 指明列值作为使用名称 AttributeName 的嵌套元素插入,而不是作为属性。
有关使用 element 指令的示例,请参见使用 element 指令。
-
xml 指明列值插入时不加引号。如果指定了 AttributeName,则值作为使用该名称的元素插入。否则,它在插入时没有包装元素。如果不使用此指令,标记字符就会被转义,除非列是 XML 类型。例如,值<a/> 会插入为 <a/>。
有关使用 xml 指令的示例,请参见使用 xml 指令。
-
cdata 指明列值要作为 CDATA 节插入。AttributeName 会被忽略。
有关使用 cdata 指令的示例,请参见使用 cdata 指令。
用法
在您执行包含 FOR XML EXPLICIT 的查询时,BINARY、LONG BINARY、IMAGE 和 VARBINARY 列中的数据会自动以 base64 编码格式返回。缺省情况下,结果集中的任何 NULL 值都会被忽略。通过更改 FOR_XML_NULL_TREATMENT 选项的设置,您可以更改这种行为。
有关 FOR_XML_NULL_TREATMENT 选项的详细信息,请参见 FOR_XML_NULL_TREATMENT 选项 [database] 和 FOR XML 和 NULL 值。
编写 EXPLICIT 模式的查询
假定您要使用 FOR XML EXPLICIT 编写一个生成以下 XML 文档的查询:
<employee emp_id='129'> <customer cust_id='107' region='Eastern'/> <customer cust_id='119' region='Western'/> <customer cust_id='131' region='Eastern'/> </employee>
<employee emp_id='195'> <customer cust_id='109' region='Eastern'/> <customer cust_id='121' region='Central'/> </employee>
实现这一点的方法是:编写一条按指定的准确顺序返回以下结果集的 SELECT 语句,然后将 FOR XML EXPLICIT 附加到该查询。
Tag | Parent | employee!1!emp_id | customer!2!cust_id | customer!2!region |
---|---|---|---|---|
1 | NULL | 129 | NULL | NULL |
2 | 1 | 129 | 107 | Eastern |
2 | 1 | 129 | 119 | Western |
2 | 1 | 129 | 131 | Central |
1 | NULL | 195 | NULL | NULL |
2 | 1 | 195 | 109 | Eastern |
2 | 1 | 195 | 121 | Central |
在您编写查询时,对于指定的行,只有部分列会成为所生成的 XML 文档的组成部分。只有在 TagNumber 字段(列名中的第二个字段)中的值与 Tag 列中的值匹配时,XML 文档中才会加入一列。
在该示例中,第三列用于两个在其 Tag 列中有值 1 的行。在第四和第五列中,值用于在其 Tag 列中有值 2 的行。元素名从列名中的第一个字段中提取。在这种情况下,会创建 <employee> 元素和 <customer> 元素。
属性名来自列名中的第三个字段,所以 emp_id 属性是为 <employee> 元素创建的,而 cust_id 属性和 region 属性是为 <customer> 元素生成的。
下面的步骤说明了如何使用示例数据库来构建一个 FOR XML EXPLICIT 查询,让该查询生成一个与本节开始时出现的 XML 文档类似的 XML 文档。
编写 FOR XML EXPLICIT 查询
-
编写 SELECT 语句以生成顶层元素。
在本示例中,查询中的第一个 SELECT 语句生成 <employee> 元素。查询中的前两个值必须是 Tag 和 Parent 列值。<employee> 元素位于层次结构的顶层,所以会给它分配一个 Tag 值 1 以及一个 Parent 值 NULL。
注意
如果您要编写一个使用 UNION 的 EXPLICIT 模式查询,则只有第一条 SELECT 语句中指定的列名才会被使用。不会用作元素名或属性名的列名必须在第一条 SELECT 语句中指定,因为在后面的 SELECT 语句中指定的列名会被忽略。要为上面的表生成 <employee> 元素,您的第一条 SELECT 语句要像下面这样:
SELECT 1 AS tag, NULL AS parent, emp_id AS [employee!1!emp_id], NULL AS [customer!2!cust_id], NULL AS [customer!2!region] FROM employee
-
编写 SELECT 语句来生成子元素。
第二个查询会生成 <customer> 元素。由于这是一个 EXPLICIT 模式查询,所以在所有 SELECT 语句中指定的前两个值都必须是 Tag 值和 Parent 值。<customer> 元素会得到标记号 2,而由于它是 <employee> 元素的子级,所以它具有 Parent 值 1。第一条 SELECT 语句已经指定了 emp_id、cust_id 和 region 都是属性。
SELECT 2, 1, emp_id, cust_id, region FROM employee KEY JOIN sales_order
-
给查询添加 UNION ALL 以便将两条 SELECT 语句合并到一起:
SELECT 1 AS tag, NULL AS parent, emp_id AS [employee!1!emp_id], NULL AS [customer!2!cust_id], NULL AS [customer!2!region] FROM employee UNION ALL
SELECT 2, 1, emp_id, cust_id, region FROM employee KEY JOIN sales_order
-
添加 ORDER BY 子句来指定结果中行的顺序。行的顺序是最终生成的文档中使用的顺序。
SELECT 1 AS tag, NULL AS parent, emp_id AS [employee!1!emp_id], NULL AS [customer!2!cust_id], NULL AS [customer!2!region] FROM employee UNION ALL
SELECT 2, 1, emp_id, cust_id, region FROM employee KEY JOIN sales_order ORDER BY 3, 1 FOR XML EXPLICIT
有关 EXPLICIT 模式的语法的信息,请参见参数。
FOR XML EXPLICIT 示例
下面的示例查询会检索有关雇员所下订单的信息。在本示例中,有三种元素:<emp>、<order> 和 <dept>。<emp> 元素具有 id 属性和 name 属性,<order> 元素具有 date 属性,<dept> 元素具有 name 属性。
SELECT 1 tag, NULL parent, emp_id [emp!1!id], emp_fname [emp!1!name], NULL [order!2!date], NULL [dept!3!name] FROM employee UNION ALL
SELECT 2, 1, emp_id, NULL, order_date, NULL FROM employee KEY JOIN sales_order UNION ALL
SELECT 3, 1, emp_id, NULL, NULL, dept_name FROM employee e JOIN department d ON e.dept_id=d.dept_id ORDER BY 3, 1 FOR XML EXPLICIT
利用此查询可以得到以下结果:
<emp id="102" name="Fran"> <dept name="R & D"/> </emp> <emp id="105" name="Matthew"> <dept name="R & D"/> </emp>
<emp id="129" name="Philip"> <order date="2000-07-24"/> <order date="2000-07-13"/> <order date="2000-06-24"/> <order date="2000-06-08"/> ... <dept name="Sales"/> </emp>
<emp id="148" name="Julie"> <dept name="Finance"/> </emp> ...
使用 element 指令
如果您想生成子元素而不是属性,可以给查询添加 element 指令,就像下面这样:
SELECT 1 tag, NULL parent, emp_id [emp!1!id!element], emp_fname [emp!1!name!element], NULL [order!2!date!element], NULL [dept!3!name!element] FROM employee
UNION ALL SELECT 2, 1, emp_id, NULL, order_date, NULL FROM employee KEY JOIN sales_order UNION ALL
SELECT 3, 1, emp_id, NULL, NULL, dept_name FROM employee e JOIN department d ON e.dept_id=d.dept_id ORDER BY 3, 1 FOR XML EXPLICIT
利用此查询可以得到以下结果:
<emp> <id>102</id> <name>Fran</name> <dept> <name>R & D</name> </dept> </emp>
<emp> <id>105</id> <name>Matthew</name> <dept> <name>R & D</name> </dept> </emp>
<emp> <id>129</id> <name>Philip</name> <order> <date>2000-07-24</date> </order> <order> <date>2000-07-13</date> </order> <order> <date>2000-06-24</date> </order> ... <dept> <name>Sales</name> </dept> </emp> ...
使用 hide 指令
在下面的查询中,雇员 ID 用于给结果排序,但结果中不会出现雇员 ID,因为指定了 hide 指令:
SELECT 1 tag, NULL parent, emp_id [emp!1!id!hide], emp_fname [emp!1!name], NULL [order!2!date], NULL [dept!3!name] FROM employee UNION ALL
SELECT 2, 1, emp_id, NULL, order_date, NULL FROM employee KEY JOIN sales_order UNION ALL
SELECT 3, 1, emp_id, NULL, NULL, dept_name FROM employee e JOIN department d ON e.dept_id=d.dept_id ORDER BY 3, 1 FOR XML EXPLICIT
此查询会返回以下结果:
<emp name="Fran"> <dept name="R & D"/> </emp> <emp name="Matthew"> <dept name="R & D"/> </emp>
<emp name="Philip"> <order date="2000-07-24"/> <order date="2000-07-13"/> <order date="2000-06-24"/> <order date="2000-06-08"/> ... <dept name="Sales"/> </emp>
<emp name="Julie"> <dept name="Finance"/> </emp> ...
使用 xml 指令
缺省情况下,当 FOR XML EXPLICIT 查询的结果包含不是有效 XML 字符的字符时,无效字符会被转义(有关信息请参见无效的列名),除非该列是 XML 类型。例如,下面的查询会生成包含"&"符号的 XML:
SELECT 1 AS tag, NULL AS parent, id AS [customer!1!id!element], company_name AS [customer!1!company_name] FROM customer WHERE id = '115' FOR XML EXPLICIT
在此查询生成的结果中,"&"符号会被转义,因为该列不是 XML 类型:
<customer company_name="Sterling & Co."> <id>115</id> </customer>
xml 指令表明列值在插入生成的 XML 中时不带引号。如果您用 xml 指令执行与上面的查询相同的查询:
SELECT 1 AS tag, NULL AS parent, id AS [customer!1!id!element], company_name AS [customer!1!company_name!xml] FROM customer WHERE id = '115' FOR XML EXPLICIT
结果中的"&"号就不会带有引号:
<customer> <id>115</id> <company_name>Sterling & Co.</company_name> </customer>
请注意,此 XML 并非结构完好,因为它包含"&"号,而这在 XML 中是一个特殊字符。当查询生成了 XML 时,您有责任确保该 XML 结构完好并且有效,因为 Adaptive Server Anywhere 不会检查所生成的 XML 是否结构完好或有效。
当您指定 xml 指令时,AttributeName 字段会被忽略,并且会生成元素而不是属性。
使用 cdata 指令
下面的查询使用 cdata 指令在 CDATA 节中返回客户名称:
SELECT 1 AS tag, NULL AS parent, id AS [product!1!id], description AS [product!1!cdata] FROM product FOR XML EXPLICIT
此查询生成的结果会在 CDATA 节中列出对每种产品的说明。CDATA 节中包含的数据不带引号:
<product id="300"> <![CDATA[Tank Top]]> </product> <product id="301"> <![CDATA[V-neck]]> </product>
<product id="302"> <![CDATA[Crew Neck]]> </product> <product id="400"> <![CDATA[Cotton Cap]]> </product> ...
使用 hide 指令
在下面的查询中,雇员 ID 用于给结果排序,但结果中不会出现雇员 ID,因为指定了 hide 指令:
SELECT 1 tag, NULL parent, emp_id [emp!1!id!hide], emp_fname [emp!1!name], NULL [order!2!date], NULL [dept!3!name] FROM employee UNION ALL
SELECT 2, 1, emp_id, NULL, order_date, NULL FROM employee KEY JOIN sales_order UNION ALL
SELECT 3, 1, emp_id, NULL, NULL, dept_name FROM employee e JOIN department d ON e.dept_id=d.dept_id ORDER BY 3, 1 FOR XML EXPLICIT
此查询会返回以下结果:
<emp name="Fran"> <dept name="R & D"/> </emp> <emp name="Matthew"> <dept name="R & D"/> </emp>
<emp name="Philip"> <order date="2000-07-24"/> <order date="2000-07-13"/> <order date="2000-06-24"/> <order date="2000-06-08"/> ... <dept name="Sales"/> </emp>
<emp name="Julie"> <dept name="Finance"/> </emp> ...
使用 xml 指令
缺省情况下,当 FOR XML EXPLICIT 查询的结果包含不是有效 XML 字符的字符时,无效字符会被转义(有关信息请参见无效的列名),除非该列是 XML 类型。例如,下面的查询会生成包含"&"符号的 XML:
SELECT 1 AS tag, NULL AS parent, id AS [customer!1!id!element], company_name AS [customer!1!company_name] FROM customer WHERE id = '115' FOR XML EXPLICIT
在此查询生成的结果中,"&"符号会被转义,因为该列不是 XML 类型:
<customer company_name="Sterling & Co."> <id>115</id> </customer>
xml 指令表明列值在插入生成的 XML 中时不带引号。如果您用 xml 指令执行与上面的查询相同的查询:
SELECT 1 AS tag, NULL AS parent, id AS [customer!1!id!element], company_name AS [customer!1!company_name!xml] FROM customer WHERE id = '115' FOR XML EXPLICIT
结果中的"&"号就不会带有引号:
<customer> <id>115</id> <company_name>Sterling & Co.</company_name> </customer>
请注意,此 XML 并非结构完好,因为它包含"&"号,而这在 XML 中是一个特殊字符。当查询生成了 XML 时,您有责任确保该 XML 结构完好并且有效,因为 Adaptive Server Anywhere 不会检查所生成的 XML 是否结构完好或有效。
当您指定 xml 指令时,AttributeName 字段会被忽略,并且会生成元素而不是属性。
使用 cdate 指令
下面的查询使用 cdata 指令在 CDATA 节中返回客户名称:
SELECT 1 AS tag, NULL AS parent, id AS [product!1!id], description AS [product!1!cdata] FROM product FOR XML EXPLICIT
此查询生成的结果会在 CDATA 节中列出对每种产品的说明。CDATA 节中包含的数据不带引号:
<product id="300"> <![CDATA[Tank Top]]> </product> <product id="301"> <![CDATA[V-neck]]> </product>
<product id="302"> <![CDATA[Crew Neck]]> </product> <product id="400"> <![CDATA[Cotton Cap]]> </product> ...