生成内联 XSD 架构

在 FOR XML 子句中,您可以请求查询同时返回内联架构和查询结果。 如果需要 XDR 架构,请使用 FOR XML 子句中的 XMLDATA 关键字。 如果需要 XSD 架构,请使用 XMLSCHEMA 关键字。

本主题介绍 XMLSCHEMA 关键字,并说明生成的内联 XSD 架构的结构。 下面是请求内联架构时的限制:

  • 只能在 RAW 和 AUTO 模式下指定 XMLSCHEMA,而不能在 EXPLICIT 模式下指定 XMLSCHEMA。

  • 如果嵌套 FOR XML 查询指定 TYPE 指令,则查询结果为 xml 类型,并且此结果被视为非类型化的 XML 数据的实例。 有关更多信息,请参阅 XML 数据 (SQL Server)

在 FOR XML 查询中指定 XMLSCHEMA 时,会收到架构和 XML 数据,即查询结果。 数据的每个顶级元素都通过使用默认命名空间声明来引用以前的架构,而该声明又引用内联架构的目标命名空间。

例如:

<xsd:schema targetNamespace="urn:schemas-microsoft-com:sql:SqlRowSet1" xmlns:schema="urn:schemas-microsoft-com:sql:SqlRowSet1" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:sqltypes="https://schemas.microsoft.com/sqlserver/2004/sqltypes" elementFormDefault="qualified">  
  <xsd:import namespace="https://schemas.microsoft.com/sqlserver/2004/sqltypes" schemaLocation="https://schemas.microsoft.com/sqlserver/2004/sqltypes/sqltypes.xsd" />  
  <xsd:element name="Production.ProductModel">  
    <xsd:complexType>  
      <xsd:attribute name="ProductModelID" type="sqltypes:int" use="required" />  
      <xsd:attribute name="Name" use="required">  
        <xsd:simpleType sqltypes:sqlTypeAlias="[AdventureWorks2012].[dbo].[Name]">  
          <xsd:restriction base="sqltypes:nvarchar" sqltypes:localeId="1033" sqltypes:sqlCompareOptions="IgnoreCase IgnoreKanaType IgnoreWidth" sqltypes:sqlSortId="52">  
            <xsd:maxLength value="50" />  
          </xsd:restriction>  
        </xsd:simpleType>  
      </xsd:attribute>  
    </xsd:complexType>  
  </xsd:element>  
</xsd:schema>  
<Production.ProductModel xmlns="urn:schemas-microsoft-com:sql:SqlRowSet1" ProductModelID="1" Name="Classic Vest" />  

结果包括 XML 架构和 XML 结果。 < ProductModel >结果中的顶级元素使用默认命名空间声明 xmlns=“urn:schemas-microsoft-com:sql:SqlRowSet1”来引用架构。

结果的架构部分可能包含描述多个命名空间的多个架构文档。 至少返回以下两个架构文档:

  • 一个用于 Sqltypes 命名空间的架构文档,该文档正在返回基本 SQL 类型。

  • 另一个描述 FOR XML 查询结果形状的架构文档。

此外,如果查询结果中包含任何类型 xml 数据类型,则包含与这些类型数据类型 xml 关联的架构。

描述 FOR XML 结果形状的架构文档的目标命名空间包含固定部分和自动递增的数字部分。 此命名空间的格式显示在以下位置,其中 n 是正整数。 例如,在前面的查询中,urn:schemas-microsoft-com:sql:SqlRowSet1 是目标命名空间。

urn:schemas-microsoft-com:sql:SqlRowSetn  

从一次执行到另一次执行,结果中目标命名空间的更改可能不理想。 例如,如果查询生成的 XML,则目标命名空间中的更改将要求更新查询。 在 FOR XML 子句中添加 XMLSCHEMA 选项时,可以选择指定目标命名空间。 生成的 XML 将包含你提供的命名空间,无论运行查询的次数如何,都将保持不变。

SELECT ProductModelID, Name  
FROM   Production.ProductModel  
WHERE ProductModelID=1  
FOR XML AUTO, XMLSCHEMA ('MyURI')  

实体元素

为了讨论为查询结果生成的 XSD 架构结构的详细信息,必须首先描述实体元素

FOR XML 查询返回的 XML 数据中的实体元素是从表而不是列生成的元素。 例如,以下 FOR XML 查询从数据库中的 Person 表中 AdventureWorks2012 返回联系信息。

SELECT BusinessEntityID, FirstName  
FROM Person.Person  
WHERE BusinessEntityID = 1  
FOR XML AUTO, ELEMENTS  

结果如下:

<Person>

<BusinessEntityID>1</BusinessEntityID>

<FirstName>Ken</FirstName>

</Person>

在此结果中, <Person> 是实体元素。 XML 结果中可以有多个实体元素,其中每个元素在内联 XSD 架构中都有一个全局声明。 例如,以下查询检索特定订单的销售订单标头和详细信息。

SELECT  SalesOrderHeader.SalesOrderID, ProductID, OrderQty  
FROM    Sales.SalesOrderHeader, Sales.SalesOrderDetail  
WHERE   SalesOrderHeader.SalesOrderID = SalesOrderDetail.SalesOrderID  
AND     SalesOrderHeader.SalesOrderID=5001  
FOR XML AUTO, ELEMENTS, XMLSCHEMA  

由于查询指定 ELEMENTS 指令,因此生成的 XML 以元素为中心。 该查询还指定 XMLSCHEMA 指令。 因此,返回内联 XSD 架构。 结果如下:

<xsd:schema targetNamespace="urn:schemas-microsoft-com:sql:SqlRowSet1" xmlns:schema="urn:schemas-microsoft-com:sql:SqlRowSet1" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:sqltypes="https://schemas.microsoft.com/sqlserver/2004/sqltypes" elementFormDefault="qualified">

<xsd:import namespace="https://schemas.microsoft.com/sqlserver/2004/sqltypes" schemaLocation="https://schemas.microsoft.com/sqlserver/2004/sqltypes/sqltypes.xsd" />

<xsd:element name="Sales.SalesOrderHeader">

<xsd:complexType>

<xsd:sequence>

<xsd:element name="SalesOrderID" type="sqltypes:int" />

<xsd:element ref="schema:Sales.SalesOrderDetail" minOccurs="0" maxOccurs="unbounded" />

</xsd:sequence>

</xsd:complexType>

</xsd:element>

<xsd:element name="Sales.SalesOrderDetail">

<xsd:complexType>

<xsd:sequence>

<xsd:element name="ProductID" type="sqltypes:int" />

<xsd:element name="OrderQty" type="sqltypes:smallint" />

</xsd:sequence>

</xsd:complexType>

</xsd:element>

</xsd:schema>

请注意上述查询的以下方面:

  • 在结果中, <SalesOrderHeader> 是 <SalesOrderDetail> 实体元素。 因此,它们在模式中被全局性声明。 也就是说,声明显示在元素内的 <Schema> 顶层。

  • OrderQty ProductID < > > <和<SalesOrderID>不是实体元素,因为它们映射到列。 由于 ELEMENTS 指令,列数据作为 XML 中的元素返回。 这些元素映射到实体元素的复杂类型的本地元素。 请注意,如果未指定 ELEMENTS 指令,则SalesOrderIDProductIDOrderQty值将映射到相应实体元素的复杂类型的本地属性。

属性名称冲突

以下讨论基于 CustOrder 表和 CustOrderDetail 表。 若要测试以下示例,请创建这些表并添加自己的示例数据:

CREATE TABLE CustOrder (OrderID int primary key, CustomerID int)  
GO  
CREATE TABLE CustOrderDetail (OrderID int, ProductID int, Qty int)  
GO  

在 FOR XML 中,有时使用相同的名称来指示不同的特性和属性。 例如,以下以属性为中心的 RAW 模式查询生成两个同名 OrderID 的属性。 这会生成错误。

SELECT CustOrder.OrderID,   
       CustOrderDetail.ProductID,   
       CustOrderDetail.OrderID  
FROM   dbo.CustOrder, dbo.CustOrderDetail  
WHERE  CustOrder.OrderID = CustOrderDetail.OrderID  
FOR XML RAW, XMLSCHEMA  

但是,由于有两个具有相同名称的元素是可以接受的,因此可以通过添加 ELEMENTS 指令来消除该问题:

SELECT CustOrder.OrderID,  
       CustOrderDetail.ProductID,   
       CustOrderDetail.OrderID  
from   dbo.CustOrder, dbo.CustOrderDetail  
where  CustOrder.OrderID = CustOrderDetail.OrderID  
FOR XML RAW, XMLSCHEMA, ELEMENTS  

结果如下: 请注意,内联 XSD 架构中定义了 OrderID 元素两次。 其中一个声明将 minOccurs 设置为 0,对应 CustOrderDetail 表中的 OrderID,第二个声明则映射到 CustOrder 表中默认情况下 minOccurs 为 1 的 OrderID 主键列。

<xsd:schema targetNamespace="urn:schemas-microsoft-com:sql:SqlRowSet1" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:sqltypes="https://schemas.microsoft.com/sqlserver/2004/sqltypes" elementFormDefault="qualified">

<xsd:import namespace="https://schemas.microsoft.com/sqlserver/2004/sqltypes" schemaLocation="https://schemas.microsoft.com/sqlserver/2004/sqltypes/sqltypes.xsd" />

<xsd:element name="row">

<xsd:complexType>

<xsd:sequence>

<xsd:element name="OrderID" type="sqltypes:int" />

<xsd:element name="ProductID" type="sqltypes:int" minOccurs="0" />

<xsd:element name="OrderID" type="sqltypes:int" minOccurs="0" />

</xsd:sequence>

</xsd:complexType>

</xsd:element>

</xsd:schema>

元素名称冲突

在 FOR XML 中,同一名称可用于指示两个子元素。 例如,以下查询检索产品的 ListPrice 和 DealerPrice 值,但查询为这两列指定了相同的别名 Price。 因此,生成的行集将具有两个具有相同名称的列。

案例 1:两个子元素都是同一类型的非键列,可以为 NULL

在以下查询中,这两个子元素都是同一类型的非键列,可以是 NULL。

DROP TABLE T  
go  
CREATE TABLE T (ProductID int primary key, ListPrice money, DealerPrice money)  
go  
INSERT INTO T values (1, 1.25, null)  
go  
  
SELECT ProductID, ListPrice Price, DealerPrice Price  
FROM   T  
for    XML RAW, ELEMENTS, XMLSCHEMA  

这是生成的相应 XML。 仅显示内联 XSD 的一小部分:

...

<xsd:schema targetNamespace="urn:schemas-microsoft-com:sql:SqlRowSet1" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:sqltypes="https://schemas.microsoft.com/sqlserver/2004/sqltypes" elementFormDefault="qualified">

<xsd:import namespace="https://schemas.microsoft.com/sqlserver/2004/sqltypes" />

<xsd:element name="row">

<xsd:complexType>

<xsd:sequence>

<xsd:element name="ProductID" type="sqltypes:int" />

<xsd:element name="Price" type="sqltypes:money" minOccurs="0" maxOccurs="2" />

</xsd:sequence>

</xsd:complexType>

</xsd:element>

</xsd:schema>

<row xmlns="urn:schemas-microsoft-com:sql:SqlRowSet1">

<ProductID>1</ProductID>

<Price>1.2500</Price>

</row>

请注意内联 XSD 模式中的以下内容:

  • ListPrice 和 DealerPrice 的类型都相同, money并且两者都可以在表中为 NULL。 因此,由于它们可能不会在生成的 XML 中返回,因此在具有 minOccurs=0 和 maxOccurs=2 的><row元素的复杂类型声明中只有一个<Price>子元素。

  • 在结果中,由于 DealerPrice 表中的值为 NULL,因此仅 ListPrice 作为 <Price> 元素返回。 如果将参数 XSINIL 添加到 ELEMENTS 指令中,那么将会收到两个元素,这些元素的 xsi:nil 值被设置为 TRUE且与对应的 DealerPrice <Price> 元素相关联。 此外,还将在内联 XSD 架构的复杂类型定义中接收两个<Price>子元素,并且这两个元素的nillable属性都设置为 TRUE。 此片段是部分结果:

...

<xsd:schema targetNamespace="urn:schemas-microsoft-com:sql:SqlRowSet1" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:sqltypes="https://schemas.microsoft.com/sqlserver/2004/sqltypes" elementFormDefault="qualified">

<xsd:import namespace="https://schemas.microsoft.com/sqlserver/2004/sqltypes" />

<xsd:element name="row">

<xsd:complexType>

<xsd:sequence>

<xsd:element name="ProductID" type="sqltypes:int" nillable="1" />

<xsd:element name="Price" type="sqltypes:money" nillable="1" />

<xsd:element name="Price" type="sqltypes:money" nillable="1" />

</xsd:sequence>

</xsd:complexType>

</xsd:element>

</xsd:schema>

<row xmlns="urn:schemas-microsoft-com:sql:SqlRowSet1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

<ProductID>1</ProductID>

<Price>1.2500</Price>

<Price xsi:nil="true" />

</row>

案例 2:同一类型的一个键和一个非键列

以下查询演示了同一类型的一个键和一个非键列。

CREATE TABLE T (Col1 int primary key, Col2 int, Col3 nvarchar(20))  
go  
INSERT INTO T VALUES (1, 1, 'test')  
go   

针对表 T 的以下查询为 Col1 和 Col2 指定相同的别名,其中 Col1 是主键,不能为 null,Col2 可以为 null。 这会生成两个同级元素,这些元素是元素的 <row> 子元素。

SELECT Col1 as Col, Col2 as Col, Col3  
FROM T  
FOR XML RAW, ELEMENTS, XMLSCHEMA  

结果如下: 仅显示内联 XSD 架构的片段。

...

<xsd:schema targetNamespace="urn:schemas-microsoft-com:sql:SqlRowSet1" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:sqltypes="https://schemas.microsoft.com/sqlserver/2004/sqltypes" elementFormDefault="qualified">

<xsd:import namespace="https://schemas.microsoft.com/sqlserver/2004/sqltypes" />

<xsd:element name="row">

<xsd:complexType>

<xsd:sequence>

<xsd:element name="Col" type="sqltypes:int" />

<xsd:element name="Col" type="sqltypes:int" minOccurs="0" />

<xsd:element name="Col3" minOccurs="0">

<xsd:simpleType>

<xsd:restriction base="sqltypes:nvarchar"

sqltypes:localeId="1033"

sqltypes:sqlCompareOptions="IgnoreCase

IgnoreKanaType IgnoreWidth"

sqltypes:sqlSortId="52">

<xsd:maxLength value="20" />

</xsd:restriction>

</xsd:simpleType>

</xsd:element>

</xsd:sequence>

</xsd:complexType>

</xsd:element>

</xsd:schema>

<row xmlns="urn:schemas-microsoft-com:sql:SqlRowSet1">

<Col>1</Col>

<Col>1</Col>

<Col3>test</Col3>

</row>

请注意,内联 XSD 架构 <Col> 中,对应于 Col2 的元素的 minOccurs 设置为 0。

案例 3:不同类型的元素及其对应的列都可以为 NULL

以下查询针对示例表指定,如 2 所示:

SELECT Col1, Col2 as Col, Col3 as Col  
FROM T  
FOR XML RAW, ELEMENTS, XMLSCHEMA  

在以下查询中,Col2 和 Col3 具有相同的别名。 这会生成两个具有相同名称的同级元素,并且它们都是结果中 <raw> 元素的子元素。 这两个列的类型不同,两个列都可以为 NULL。 结果如下: 仅显示部分内联 XSD 架构。

...

<xsd:schema targetNamespace="urn:schemas-microsoft-com:sql:SqlRowSet1" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:sqltypes="https://schemas.microsoft.com/sqlserver/2004/sqltypes" elementFormDefault="qualified">

<xsd:import namespace="https://schemas.microsoft.com/sqlserver/2004/sqltypes" />

<xsd:simpleType name="Col1">

<xsd:restriction base="sqltypes:int" />

</xsd:simpleType>

<xsd:simpleType name="Col2">

<xsd:restriction base="sqltypes:nvarchar" sqltypes:localeId="1033"

sqltypes:sqlCompareOptions="IgnoreCase

IgnoreKanaType IgnoreWidth" sqltypes:sqlSortId="52">

<xsd:maxLength value="20" />

</xsd:restriction>

</xsd:simpleType>

<xsd:element name="row">

<xsd:complexType>

<xsd:sequence>

<xsd:element name="Col1" type="sqltypes:int" />

<xsd:element name="Col" minOccurs="0" maxOccurs="2" type="xsd:anySimpleType" />

</xsd:sequence>

</xsd:complexType>

</xsd:element>

</xsd:schema>

<row xmlns="urn:schemas-microsoft-com:sql:SqlRowSet1">

<Col1>1</Col1>

<Col xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:type="Col1">1</Col>

<Col xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:type="Col2">test</Col>

</row>

请注意内联 XSD 架构中的以下内容:

  • 由于 Col2 和 Col3 可以是 NULL, <Col> 因此元素声明将 minOccurs 指定为 0,maxOccurs 指定为 2。

  • 由于这 <Col> 两个元素都是同级元素,因此架构中有一个元素声明。 此外,由于这两个元素也是不同类型的,尽管这两个元素都是简单的类型,但架构中的元素的类型是 xsd:anySimpleType。 在结果中,每个实例类型都由 xsi:type 属性标识。

  • 在结果中,元素的每个实例 <Col> 都使用 xsi:type 特性引用其实例类型。