以下示例演示如何在从 SELECT 查询生成 XML 时使用 PATH 模式。 其中许多查询针对存储在 ProductModel 表的“指令”列中的自行车制造指令 XML 文档指定。
指定简单的 PATH 模式查询
此查询指定 FOR XML PATH 模式。
USE AdventureWorks2012;
GO
SELECT
ProductModelID,
Name
FROM Production.ProductModel
WHERE ProductModelID=122 OR ProductModelID=119
FOR XML PATH;
GO
以下结果是以元素为中心的 XML,其中生成的行集中的每个列值都包装在元素中。 由于子 SELECT 句未指定列名的任何别名,因此生成的子元素名称与子句中的 SELECT 相应列名相同。 对于行集中的每一行,将添加一个 <row> 标记。
<row>
<ProductModelID>122</ProductModelID>
<Name>All-Purpose Bike Stand</Name>
</row>
<row>
<ProductModelID>119</ProductModelID>
<Name>Bike Wash</Name>
</row>
以下结果与使用 ELEMENTS 选项的 RAW 模式查询结果相同。 它返回以元素为中心的 XML,其中包含结果集中每一行的默认 <row> 元素。
USE AdventureWorks2012;
GO
SELECT ProductModelID,
Name
FROM Production.ProductModel
WHERE ProductModelID=122 OR ProductModelID=119
FOR XML RAW, ELEMENTS;
可以选择指定行元素名称以覆盖默认值 <row>。 例如,以下查询将返回行集中每一行的<ProductModel>元素。
USE AdventureWorks2012;
GO
SELECT ProductModelID,
Name
FROM Production.ProductModel
WHERE ProductModelID=122 or ProductModelID=119
FOR XML PATH ('ProductModel');
GO
生成的 XML 将具有指定的行元素名称。
<ProductModel>
<ProductModelID>122</ProductModelID>
<Name>All-Purpose Bike Stand</Name>
</ProductModel>
<ProductModel>
<ProductModelID>119</ProductModelID>
<Name>Bike Wash</Name>
</ProductModel>
如果指定零长度字符串,则不生成包装元素。
USE AdventureWorks2012;
GO
SELECT ProductModelID,
Name
FROM Production.ProductModel
WHERE ProductModelID=122 OR ProductModelID=119
FOR XML PATH ('');
GO
结果如下:
<ProductModelID>122</ProductModelID>
<Name>All-Purpose Bike Stand</Name>
<ProductModelID>119</ProductModelID>
<Name>Bike Wash</Name>
指定类似于 XPath 的列名称
在以下查询中, ProductModelID 指定的列名以“@”开头,不包含斜杠标记('/')。 因此,在生成的 XML 中创建具有相应列值的元素的属性 <row> 。
USE AdventureWorks2012;
GO
SELECT ProductModelID AS "@id",
Name
FROM Production.ProductModel
WHERE ProductModelID=122 OR ProductModelID=119
FOR XML PATH ('ProductModelData');
GO
结果如下:
< ProductModelData id="122">
<Name>All-Purpose Bike Stand</Name>
</ ProductModelData >
< ProductModelData id="119">
<Name>Bike Wash</Name>
</ ProductModelData >
可以通过在FOR XML中指定root选项来添加单个顶级元素。
SELECT ProductModelID AS "@id",
Name
FROM Production.ProductModel
WHERE ProductModelID=122 or ProductModelID=119
FOR XML PATH ('ProductModelData'), root ('Root');
GO
若要生成层次结构,可以包含类似于 PATH 的语法。 例如,将列的 Name 列名称更改为“SomeChild/ModelName”,你将获得具有层次结构的 XML,如以下结果所示:
<Root>
<ProductModelData id="122">
<SomeChild>
<ModelName>All-Purpose Bike Stand</ModelName>
</SomeChild>
</ProductModelData>
<ProductModelData id="119">
<SomeChild>
<ModelName>Bike Wash</ModelName>
</SomeChild>
</ProductModelData>
</Root>
除了产品型号 ID 和名称,以下查询还检索产品模型的制造说明位置。 由于“指令”列是xml类型,因此指定使用xml数据类型的方法query()来检索位置。
SELECT ProductModelID AS "@id",
Name,
Instructions.query('declare namespace MI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
/MI:root/MI:Location
') AS ManuInstr
FROM Production.ProductModel
WHERE ProductModelID = 7
FOR XML PATH ('ProductModelData'), root ('Root');
GO
下面是部分结果: 由于查询将 ManuInstr 指定为列名,因此该方法返回的 XML 被 <ManuInstr> 标签包裹,如下所示:
<Root>
<ProductModelData id="7">
<Name>HL Touring Frame</Name>
<ManuInstr>
<MI:Location xmlns:MI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions"
<MI:step>...</MI:step>...
</MI:Location>
...
</ManuInstr>
</ProductModelData>
</Root>
在上一个 FOR XML 查询中,你可能希望为元素 <Root> 和 <ProductModelData> 包含命名空间。 要做到这一点,可以先使用 WITH XMLNAMESPACES 定义到命名空间绑定的前缀,然后在 FOR XML 查询中使用这些前缀。 有关详细信息,请参阅 使用 WITH XMLNAMESPACES 向查询添加命名空间。
USE AdventureWorks2012;
GO
WITH XMLNAMESPACES (
'uri1' AS ns1,
'uri2' AS ns2,
'https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions' as MI)
SELECT ProductModelID AS "ns1:ProductModelID",
Name AS "ns1:Name",
Instructions.query('
/MI:root/MI:Location
')
FROM Production.ProductModel
WHERE ProductModelID=7
FOR XML PATH ('ns2:ProductInfo'), root('ns1:root');
GO
请注意,前缀MI也在WITH XMLNAMESPACES中被定义。 因此,指定的xml类型的方法query()不会在查询前言中定义前缀。 结果如下:
<ns1:root xmlns:MI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions" xmlns="uri2" xmlns:ns2="uri2" xmlns:ns1="uri1">
<ns2:ProductInfo>
<ns1:ProductModelID>7</ns1:ProductModelID>
<ns1:Name>HL Touring Frame</ns1:Name>
<MI:Location xmlns:MI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions"
LaborHours="2.5" LotSize="100" MachineHours="3" SetupHours="0.5" LocationID="10" xmlns="">
<MI:step>
Insert <MI:material>aluminum sheet MS-2341</MI:material> into the <MI:tool>T-85A framing tool</MI:tool>.
</MI:step>
...
</MI:Location>
...
</ns2:ProductInfo>
</ns1:root>
使用 PATH 模式生成值列表
对于每个产品模型,此查询将构造产品 ID 的值列表。 对于每个产品 ID,查询还构造 <ProductName> 嵌套元素,如以下 XML 片段所示:
<ProductModelData ProductModelID="7" ProductModelName="..."
ProductIDs="product id list in the product model" >
<ProductName>...</ProductName>
<ProductName>...</ProductName>
...
</ProductModelData>
这是生成所需 XML 的查询:
USE AdventureWorks2012;
GO
SELECT ProductModelID AS "@ProductModelID",
Name S "@ProductModelName",
(SELECT ProductID AS "data()"
FROM Production.Product
WHERE Production.Product.ProductModelID =
Production.ProductModel.ProductModelID
FOR XML PATH ('')) S "@ProductIDs",
(SELECT Name AS "ProductName"
FROM Production.Product
WHERE Production.Product.ProductModelID =
Production.ProductModel.ProductModelID
FOR XML PATH ('')) as "ProductNames"
FROM Production.ProductModel
WHERE ProductModelID= 7 or ProductModelID=9
FOR XML PATH('ProductModelData');
请注意上述查询的以下方面:
第一个嵌套
SELECT返回 ProductID 列表,使用data()作为列名。 由于查询将空字符串指定为行元素名称,FOR XML PATH因此不会生成任何元素。 而是将值列表分配给ProductID属性。第二个嵌套
SELECT的功能是从产品模型中检索产品名称。 它生成<ProductName>元素,这些元素被包装在<ProductNames>元素中返回,因为查询指定ProductNames为列名。
下面是部分结果:
<ProductModelData PId="7"
ProductModelName="HL Touring Frame"
ProductIDs="885 887 ...">
<ProductNames>
<ProductName>HL Touring Frame - Yellow, 60</ProductName>
<ProductName>HL Touring Frame - Yellow, 46</ProductName></ProductNames>
...
</ProductModelData>
<ProductModelData PId="9"
ProductModelName="LL Road Frame"
ProductIDs="722 723 724 ...">
<ProductNames>
<ProductName>LL Road Frame - Black, 58</ProductName>
<ProductName>LL Road Frame - Black, 60</ProductName>
<ProductName>LL Road Frame - Black, 62</ProductName>
...
</ProductNames>
</ProductModelData>
构造产品名称的子查询将返回结果作为字符串进行实体化,然后添加到 XML。 如果添加 type 指令, FOR XML PATH (''), type则子查询将返回类型 xml 的结果,并且不会发生实体化。
USE AdventureWorks2012;
GO
SELECT ProductModelID AS "@ProductModelID",
Name AS "@ProductModelName",
(SELECT ProductID AS "data()"
FROM Production.Product
WHERE Production.Product.ProductModelID =
Production.ProductModel.ProductModelID
FOR XML PATH ('')
) AS "@ProductIDs",
(
SELECT Name AS "ProductName"
FROM Production.Product
WHERE Production.Product.ProductModelID =
Production.ProductModel.ProductModelID
FOR XML PATH (''), type
) AS "ProductNames"
FROM Production.ProductModel
WHERE ProductModelID= 7 OR ProductModelID=9
FOR XML PATH('ProductModelData');
在生成的 XML 中添加命名空间
如使用 WITH XMLNAMESPACES 添加命名空间中所述,可以使用 WITH XMLNAMESPACES 在 PATH 模式查询中包含命名空间。 例如,SELECT 子句中指定的名称包括命名空间前缀。 以下 PATH 模式查询使用命名空间构造 XML。
SELECT 'en' as "English/@xml:lang",
'food' as "English",
'ger' as "German/@xml:lang",
'Essen' as "German"
FOR XML PATH ('Translation')
GO
@xml:lang添加到<English>元素的属性在预定义的 xml 命名空间中定义。
结果如下:
<Translation>
<English xml:lang="en">food</English>
<German xml:lang="ger">Essen</German>
</Translation>
以下查询类似于示例 C,只不过它使用 WITH XMLNAMESPACES 将命名空间包含在 XML 结果中。 有关详细信息,请参阅 使用 WITH XMLNAMESPACES 向查询添加命名空间。
USE AdventureWorks2012;
GO
WITH XMLNAMESPACES ('uri1' AS ns1, DEFAULT 'uri2')
SELECT ProductModelID AS "@ns1:ProductModelID",
Name AS "@ns1:ProductModelName",
(SELECT ProductID AS "data()"
FROM Production.Product
WHERE Production.Product.ProductModelID =
Production.ProductModel.ProductModelID
FOR XML PATH ('')
) AS "@ns1:ProductIDs",
(
SELECT ProductID AS "@ns1:ProductID",
Name AS "@ns1:ProductName"
FROM Production.Product
WHERE Production.Product.ProductModelID =
Production.ProductModel.ProductModelID
FOR XML PATH , type
) AS "ns1:ProductNames"
FROM Production.ProductModel
WHERE ProductModelID= 7 OR ProductModelID=9
FOR XML PATH('ProductModelData'), root('root');
结果如下:
<root xmlns="uri2" xmlns:ns1="uri1">
<ProductModelData ns1:ProductModelID="7" ns1:ProductModelName="HL Touring Frame" ns1:ProductIDs="885 887 888 889 890 891 892 893">
<ns1:ProductNames>
<row xmlns="uri2" xmlns:ns1="uri1" ns1:ProductID="885" ns1:ProductName="HL Touring Frame - Yellow, 60" />
<row xmlns="uri2" xmlns:ns1="uri1" ns1:ProductID="887" ns1:ProductName="HL Touring Frame - Yellow, 46" />
...
</ns1:ProductNames>
</ProductModelData>
<ProductModelData ns1:ProductModelID="9" ns1:ProductModelName="LL Road Frame" ns1:ProductIDs="722 723 724 725 726 727 728 729 730 736 737 738">
<ns1:ProductNames>
<row xmlns="uri2" xmlns:ns1="uri1" ns1:ProductID="722" ns1:ProductName="LL Road Frame - Black, 58" />
...
</ns1:ProductNames>
</ProductModelData>
</root>