Compartilhar via


Gerar um esquema XSD embutido

Em uma cláusula FOR XML, você pode solicitar que sua consulta retorne um esquema embutido junto com os resultados da consulta. Se você quiser um esquema XDR, use a palavra-chave XMLDATA na cláusula FOR XML. Se você quiser um esquema XSD, use a palavra-chave XMLSCHEMA.

Este tópico descreve a palavra-chave XMLSCHEMA e explica a estrutura do esquema XSD embutido resultante. A seguir estão as limitações ao solicitar esquemas inline:

  • Você pode especificar XMLSCHEMA somente no modo RAW e AUTO, não no modo EXPLICIT.

  • Se uma consulta FOR XML aninhada especificar a diretiva TYPE, o resultado da consulta será do xml tipo e esse resultado será tratado como uma instância de dados XML não tipados. Para obter mais informações, consulte Dados XML (SQL Server).

Quando você especifica XMLSCHEMA em uma consulta FOR XML, recebe um esquema e dados XML, o resultado da consulta. Cada elemento de nível superior dos dados refere-se ao esquema anterior usando uma declaração de namespace padrão que, por sua vez, se refere ao namespace de destino do esquema embutido.

Por exemplo:

<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" />  

O resultado inclui o esquema XML e o resultado XML. O <ProductModel> elemento de nível superior no resultado refere-se ao esquema usando a declaração de namespace padrão, xmlns="urn:schemas-microsoft-com:sql:SqlRowSet1" .

A parte do esquema do resultado pode conter vários documentos de esquema que descrevem vários namespaces. No mínimo, os dois documentos de esquema a seguir são retornados:

  • Um documento de esquema para o namespace sqltypes e para o qual os tipos de SQL base estão sendo retornados.

  • Outro documento de esquema que descreve a forma do resultado da consulta FOR XML.

Além disso, se qualquer tipo de dados tipado xml for incluído no resultado da consulta, os esquemas associados a esses tipos de dados digitados xml serão incluídos.

O namespace de destino do documento de esquema que descreve a forma do resultado FOR XML contém uma parte fixa e uma parte numérica que é incrementada automaticamente. O formato desse namespace é mostrado no seguinte, em que n é um inteiro positivo. Por exemplo, na consulta anterior, urn:schemas-microsoft-com:sql:SqlRowSet1 é o namespace de destino.

urn:schemas-microsoft-com:sql:SqlRowSetn  

A alteração nos namespaces de destino no resultado que ocorreu de uma execução para outra pode não ser desejável. Por exemplo, se você consultar o XML resultante, a alteração no namespace de destino exigirá que você atualize sua consulta. Opcionalmente, você pode especificar um namespace de destino quando a opção XMLSCHEMA for adicionada à cláusula FOR XML. O XML resultante incluirá o namespace fornecido e permanecerá o mesmo, independentemente de quantas vezes você executar a consulta.

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

Elementos de entidade

Para discutir os detalhes da estrutura de esquema XSD gerada para o resultado da consulta, o elemento de entidade deve ser descrito primeiro

Um elemento de entidade nos dados XML retornados pela consulta FOR XML é um elemento gerado a partir de uma tabela e não de uma coluna. Por exemplo, a consulta FOR XML a seguir retorna informações de contato da Person tabela no AdventureWorks2012 banco de dados.

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

Este é o resultado:

<Person>

<BusinessEntityID>1</BusinessEntityID>

<FirstName>Ken</FirstName>

</Person>

Nesse resultado, <Person> é o elemento de entidade. Pode haver vários elementos de entidade no resultado XML e cada um deles tem uma declaração global no esquema XSD embutido. Por exemplo, a consulta a seguir recupera o cabeçalho do pedido de vendas e informações detalhadas para um pedido específico.

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

Como a consulta especifica a diretiva ELEMENTS, o XML resultante é centrado em elementos. A consulta também especifica a diretiva XMLSCHEMA. Portanto, um esquema XSD embutido é retornado. Este é o resultado:

<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>

Observe o seguinte na consulta anterior:

  • No resultado, <SalesOrderHeader> e <SalesOrderDetail> são elementos de entidade. Por isso, eles são declarados globalmente no esquema. Ou seja, a declaração aparece no nível superior dentro do <Schema> elemento.

  • Os <SalesOrderID>, <ProductID> e <OrderQty> não são elementos de entidade, porque eles são mapeados para colunas. Os dados da coluna são retornados como elementos no XML, devido à diretiva ELEMENTS. Eles são mapeados para elementos locais do tipo complexo do elemento da entidade. Observe que, se a diretiva ELEMENTS não for especificada, os valores SalesOrderID, ProductID e OrderQty serão mapeados para atributos locais do tipo complexo do elemento de entidade correspondente.

Conflitos de nome de atributo

A discussão a seguir é baseada nas tabelas CustOrder e CustOrderDetail. Para testar os exemplos a seguir, crie estas tabelas e adicione seus próprios dados de exemplo:

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

No FOR XML, o mesmo nome às vezes é usado para indicar propriedades diferentes, atributos. Por exemplo, a consulta de modo RAW centrada no atributo a seguir gera dois atributos que têm o mesmo nome, OrderID. Isso gera um erro.

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

No entanto, como é aceitável ter dois elementos que têm o mesmo nome, você pode eliminar o problema adicionando a diretiva ELEMENTS:

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

Este é o resultado. Observe que, no esquema XSD embutido, o elemento OrderID é definido duas vezes. Uma das declarações tem minOccurs definido como 0, correspondente à OrderID da tabela CustOrderDetail, e a segunda mapeia para a coluna de chave primária OrderID da tabela CustOrder, em que minOccurs é 1 por padrão.

<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>

Conflitos de nome do elemento

No FOR XML, o mesmo nome pode ser usado para indicar dois subelementos. Por exemplo, a consulta a seguir recupera os valores ListPrice e DealerPrice de produtos, mas a consulta especifica o mesmo alias, Price, para essas duas colunas. Portanto, o conjunto de linhas resultante terá duas colunas com o mesmo nome.

Caso 1: Ambos os subelementos são colunas não chave do mesmo tipo e podem ser NULL

Na consulta a seguir, ambos os subelementos são colunas não chave do mesmo tipo e podem ser 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  

Esse é o XML correspondente gerado. Apenas uma fração do XSD embutido é mostrada:

...

<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>

Observe o seguinte no esquema XSD embutido:

  • ListPrice e DealerPrice são do mesmo tipo moneye ambos podem ser NULL na tabela. Portanto, como eles podem não ser retornados no XML resultante, há apenas um <Price> elemento filho na declaração de tipo complexo do <row> elemento que tem minOccurs=0 e maxOccurs=2.

  • No resultado, como o DealerPrice valor é NULL na tabela, só ListPrice é retornado como um <Price> elemento. Se você adicionar o XSINIL parâmetro à diretiva ELEMENTS, receberá ambos os elementos que têm o xsi:nil valor definido como TRUE para o<Price> elemento que corresponde a DealerPrice. Você também receberá dois <Price> elementos filho na><rowdefinição de tipo complexo no esquema XSD embutido com o nillable atributo definido como TRUE para ambos. Esse fragmento é um resultado parcial:

...

<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>

Caso 2: uma chave e uma coluna não chave do mesmo tipo

A consulta a seguir ilustra uma chave e uma coluna não chave do mesmo tipo.

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

A consulta a seguir na tabela T especifica o mesmo alias para Col1 e Col2, em que Col1 é uma chave primária e não pode ser nula, e Col2 pode ser nulo. Isso gera dois elementos irmãos que são filhos do <row> elemento.

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

Este é o resultado. Apenas um fragmento do esquema XSD embutido é mostrado.

...

<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>

Observe no esquema XSD embutido que o <Col> elemento correspondente ao Col2 tem minOccurs definido como 0.

Caso 3: ambos os elementos de tipos diferentes e colunas correspondentes podem ser NULL

A consulta a seguir é especificada na tabela de exemplo mostrada no caso 2:

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

Na consulta a seguir, Col2 e Col3 recebem os mesmos aliases. Isso gera dois elementos irmãos que têm o mesmo nome e que são filhos do <raw> elemento no resultado. Ambas as colunas são de tipos diferentes e ambas podem ser NULL. Este é o resultado. Somente o esquema XSD em linha parcial é mostrado.

...

<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>

Observe o seguinte no esquema XSD embutido:

  • Como col2 e Col3 podem ser NULL, a declaração de <Col> elemento especifica o minOccurs como 0 e maxOccurs como 2.

  • Como ambos os <Col> elementos são irmãos, há uma declaração de elemento no esquema. Além disso, como ambos os elementos também são de tipos diferentes, embora ambos sejam tipos simples, o tipo do elemento no esquema é xsd:anySimpleType. No resultado, cada tipo de instância é identificado pelo xsi:type atributo.

  • No resultado, cada instância do <Col> elemento refere-se ao tipo de instância usando o xsi:type atributo.