使用 WITH XMLNAMESPACES 将命名空间添加到查询

WITH XMLNAMESPACES (Transact-SQL) 通过以下方式提供命名空间 URI 支持:

在 FOR XML 查询中使用 WITH XMLNAMESPACES

WITH XMLNAMESPACES 允许在 FOR XML 查询中包含 XML 命名空间。 例如,请考虑以下 FOR XML 查询:

SELECT ProductID, Name, Color  
FROM   Production.Product  
WHERE  ProductID=316 or ProductID=317  
FOR XML RAW  

结果如下:

<row ProductID="316" Name="Blade" />  
<row ProductID="317" Name="LL Crankarm" Color="Black" />  
  

若要将命名空间添加到 FOR XML 查询构造的 XML,请先使用 WITH NAMESPACES 子句将命名空间前缀指定为 URI 映射。 然后,在指定查询中的名称时使用命名空间前缀,如以下修改后的查询所示。 请注意,WITH XMLNAMESPACES 子句指定命名空间前缀 (ns1) 到 URI (uri) 映射。 然后,该 ns1 前缀用于指定要由 FOR XML 查询构造的元素和属性名称。

WITH XMLNAMESPACES ('uri' as ns1)  
SELECT ProductID as 'ns1:ProductID',  
       Name      as 'ns1:Name',   
       Color     as 'ns1:Color'  
FROM Production.Product  
WHERE ProductID=316 or ProductID=317  
FOR XML RAW ('ns1:Prod'), ELEMENTS  
  

XML 结果包括命名空间前缀:

<ns1:Prod xmlns:ns1="uri">  
  <ns1:ProductID>316</ns1:ProductID>  
  <ns1:Name>Blade</ns1:Name>  
</ns1:Prod>  
<ns1:Prod xmlns:ns1="uri">  
  <ns1:ProductID>317</ns1:ProductID>  
  <ns1:Name>LL Crankarm</ns1:Name>  
  <ns1:Color>Black</ns1:Color>  
</ns1:Prod>  
  

以下内容适用于 WITH XMLNAMESPACES 子句:

  • 它仅在 FOR XML 查询的 RAW、AUTO 和 PATH 模式下受支持。 不支持 EXPLICIT 模式。

  • 它只影响 FOR XML 查询和 xml 数据类型方法的命名空间前缀,但不影响 XML 分析程序。 例如,以下查询返回错误,因为 XML 文档没有 myNS 前缀的命名空间声明。

  • 使用 WITH XMLNAMESPACES 子句时,不能使用 FOR XML 指令、XMLSCHEMA 和 XMLDATA。

    CREATE TABLE T (x xml)  
    go  
    WITH XMLNAMESPACES ('http://abc' as myNS )  
    INSERT INTO T VALUES('<myNS:root/>')  
    

使用 XSINIL 指令

如果使用 ELEMENTS XSINIL 指令,则不能在 WITH XMLNAMESPACES 子句中定义 xsi 前缀。 而是在使用 ELEMENTS XSINIL 时自动添加它。 以下查询使用 ELEMENTS XSINIL 生成以元素为中心的 XML,其中 null 值映射到将 xsi:nil 属性设置为 True 的元素。

WITH XMLNAMESPACES ('uri' as ns1)  
SELECT ProductID as 'ns1:ProductID',  
       Name      as 'ns1:Name',   
       Color     as 'ns1:Color'  
FROM Production.Product  
WHERE ProductID=316   
FOR XML RAW, ELEMENTS XSINIL  

结果如下:

<row xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns1="uri">  
  <ns1:ProductID>316</ns1:ProductID>  
  <ns1:Name>Blade</ns1:Name>  
  <ns1:Color xsi:nil="true" />  
</row>  

指定默认命名空间

可以使用 DEFAULT 关键字来声明默认命名空间,而不是声明命名空间前缀。 在 FOR XML 查询中,它将默认命名空间绑定到生成的 XML 中的 XML 节点。 在以下示例中,WITH XMLNAMESPACES 定义两个命名空间前缀,这些前缀与默认命名空间一起定义。

WITH XMLNAMESPACES ('uri1' as ns1,   
                    'uri2' as ns2,  
                    DEFAULT 'uri2')  
SELECT ProductID,   
      Name,  
      Color  
FROM Production.Product   
WHERE ProductID=316 or ProductID=317  
FOR XML RAW ('ns1:Product'), ROOT('ns2:root'), ELEMENTS  

FOR XML 查询生成以元素为中心的 XML。 请注意,查询在命名节点中同时使用命名空间前缀。 在 SELECT 子句中,ProductID、Name 和 Color 不指定具有任何前缀的名称。 因此,生成的 XML 中的相应元素属于默认命名空间。

<ns2:root xmlns="uri2" xmlns:ns2="uri2" xmlns:ns1="uri1">  
  <ns1:Product>  
    <ProductID>316</ProductID>  
    <Name>Blade</Name>  
  </ns1:Product>  
  <ns1:Product>  
    <ProductID>317</ProductID>  
    <Name>LL Crankarm</Name>  
    <Color>Black</Color>  
  </ns1:Product>  
</ns2:root>  

以下查询类似于上一个查询,只是指定了 FOR XML AUTO 模式。

WITH XMLNAMESPACES ('uri1' as ns1,  'uri2' as ns2,DEFAULT 'uri2')  
SELECT ProductID,   
      Name,  
      Color  
FROM Production.Product as "ns1:Product"  
WHERE ProductID=316 or ProductID=317  
FOR XML AUTO, ROOT('ns2:root'), ELEMENTS  

使用预定义命名空间

使用预定义命名空间时,除使用 ELEMENTS XSINIL 时的 xml 命名空间和 xsi 命名空间外,必须使用 WITH XMLNAMESPACES 显式指定命名空间绑定。 以下查询显式定义预定义命名空间的 URI 绑定的命名空间前缀(urn:schemas-microsoft-com:xml-sql)。

WITH XMLNAMESPACES ('urn:schemas-microsoft-com:xml-sql' as sql)  
SELECT 'SELECT * FROM Customers FOR XML AUTO, ROOT("a")' AS "sql:query"  
FOR XML PATH('sql:root')  

结果如下: SQLXML 用户熟悉此 XML 模板。 有关详细信息,请参阅 SQLXML 4.0 编程概念

<sql:root xmlns:sql="urn:schemas-microsoft-com:xml-sql">  
  <sql:query>SELECT * FROM Customers FOR XML AUTO, ROOT("a")</sql:query>  
</sql:root>  

只有 xml 命名空间前缀才能使用,而无需在 WITH XMLNAMESPACES 中显式定义它,如以下 PATH 模式查询所示。 此外,如果声明前缀,则必须绑定到命名空间 http://www.w3.org/XML/1998/namespace。 SELECT 子句中指定的名称是指未使用 WITH XMLNAMESPACES 显式定义的 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 属性使用预定义的 xml 命名空间。 由于 XML 版本 1.0 不需要 xml 命名空间绑定的显式声明,因此结果将不包括命名空间绑定的显式声明。

结果如下:

<Translation>  
  <English xml:lang="en">food</English>  
  <German xml:lang="ger">Essen</German>  
</Translation>  

将 WITH XMLNAMESPACES 与 xml 数据类型方法配合使用

在 SELECT 查询中指定的 xml 数据类型方法 ,或者在 UPDATE 中指定为 modify() 方法时,所有方法必须在其 prolog 中重复命名空间声明。 这很耗时。 例如,以下查询检索目录说明中包含规格的产品型号 ID。 也就是说,该 <Specifications> 元素存在。

SELECT ProductModelID, CatalogDescription.query('  
declare namespace pd="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription";  
    <Product   
        ProductModelID= "{ sql:column("ProductModelID") }"   
        />  
') AS Result  
FROM Production.ProductModel  
WHERE CatalogDescription.exist('  
    declare namespace  pd="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription";  
     /pd:ProductDescription[(pd:Specifications)]'  
    ) = 1  

在前面的查询中, query()exist() 方法在其 prolog 中声明相同的命名空间。 例如:

declare namespace pd="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription";  

或者,可以首先声明 WITH XMLNAMESPACES,并在查询中使用命名空间前缀。 在这种情况下, query()exist() 方法不必在其 prolog 中包含命名空间声明。

WITH XMLNAMESPACES ('https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription' as pd)  
SELECT ProductModelID, CatalogDescription.query('  
    <Product   
        ProductModelID= "{ sql:column("ProductModelID") }"   
        />  
') AS Result  
FROM Production.ProductModel  
WHERE CatalogDescription.exist('  
     /pd:ProductDescription[(pd:Specifications)]'  
    ) = 1  
Go  

请注意,XQuery prolog 中的显式声明将替代命名空间前缀和 WITH 子句中定义的默认元素命名空间。

另请参阅

xml 数据类型方法
Xquery 语言参考 (SQL Server)
WITH XMLNAMESPACES (Transact-SQL)
FOR XML (SQL Server)