Delen via


Een inline XSD-schema genereren

van toepassing op:SQL ServerAzure SQL Database-

In een FOR XML-component kunt u aanvragen dat uw query samen met de queryresultaten een inlineschema retourneert. Als u een XDR-schema wilt, gebruikt u het trefwoord XMLDATA in de FOR XML-component. Als u een XSD-schema wilt, gebruikt u het trefwoord XMLSCHEMA.

In dit artikel wordt het XMLSCHEMA-trefwoord beschreven en wordt de structuur van het resulterende XSD-schema inline uitgelegd. Hier volgen de beperkingen wanneer u inlineschema's aanvraagt:

  • U kunt XMLSCHEMA alleen opgeven in de RAW- en AUTO-modus, niet in expliciete modus.

  • Als een geneste FOR XML-query de TYPE-instructie opgeeft, is het queryresultaat van xml- type en dit resultaat wordt behandeld als een exemplaar van niet-getypte XML-gegevens. Zie XML Data (SQL Server)voor meer informatie.

Wanneer u XMLSCHEMA opgeeft in een FOR XML-query, ontvangt u zowel een schema als XML-gegevens, het queryresultaat. Elk element op het hoogste niveau van de gegevens verwijst naar het vorige schema met behulp van een standaardnaamruimtedeclaratie die op zijn beurt verwijst naar de doelnaamruimte van het inlineschema.

Bijvoorbeeld:

<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="[AdventureWorks2022].[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" />

Het resultaat bevat een XML-schema en het XML-resultaat. Het <ProductModel> element op het hoogste niveau in het resultaat verwijst naar het schema met behulp van de standaardnaamruimtedeclaratie xmlns="urn:schemas-microsoft-com:sql:SqlRowSet1".

Het schemagedeelte van het resultaat kan meerdere schemadocumenten bevatten die meerdere naamruimten beschrijven. Minimaal worden de volgende twee schemadocumenten geretourneerd:

  • Eén schemadocument voor de Sqltypes naamruimte en waarvoor de basis-SQL-typen worden geretourneerd.

  • Een ander schemadocument waarin de vorm van het RESULTAAT van de FOR XML-query wordt beschreven.

Als er getypte xml- gegevenstypen in het queryresultaat zijn opgenomen, worden ook de schema's opgenomen die verbonden zijn met die getypte xml- gegevenstypen.

De doelnaamruimte van het schemadocument waarin de vorm van het FOR XML-resultaat wordt beschreven, bevat een vast gedeelte en een numeriek gedeelte dat automatisch wordt verhoogd. De indeling van deze naamruimte wordt weergegeven in het volgende, waarbij n een positief geheel getal is. In de vorige query is urn:schemas-microsoft-com:sql:SqlRowSet1 bijvoorbeeld de doelnaamruimte.

urn:schemas-microsoft-com:sql:SqlRowSetn

De verandering in de doelnaamruimten in het resultaat die van de ene uitvoering naar de andere optrad, is wellicht niet gewenst. Als u bijvoorbeeld een query uitvoert op de resulterende XML, vereist de wijziging in de doelnaamruimte dat u uw query bijwerkt. U kunt desgewenst een doelnaamruimte opgeven wanneer de optie XMLSCHEMA wordt toegevoegd in de FOR XML-component. De resulterende XML bevat de naamruimte die u hebt opgegeven en blijft hetzelfde, ongeacht hoe vaak u de query uitvoert.

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

Entiteitselementen

Als u de details wilt bespreken van de XSD-schemastructuur die is gegenereerd voor het queryresultaat, moet het entiteitselement eerst worden beschreven

Een entiteitselement in de XML-gegevens die door FOR XML-query worden geretourneerd, is een element dat wordt gegenereerd op basis van een tabel en niet uit een kolom. De volgende FOR XML-query retourneert bijvoorbeeld contactgegevens uit de Person tabel in de AdventureWorks2022-database.

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

Dit is het resultaat:

<Person>
  <BusinessEntityID>1</BusinessEntityID>
  <FirstName>Ken</FirstName>
</Person>

In dit resultaat is <Person> het entiteitselement. Er kunnen meerdere entiteitselementen in het XML-resultaat zijn en elk van deze elementen heeft een globale declaratie in het inline XSD-schema. Met de volgende query worden bijvoorbeeld header- en detailgegevens van verkooporders opgehaald voor een specifieke order.

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

Omdat de query de ELEMENTS-instructie specificeert, is de resulterende XML elementgericht. De query geeft ook de XMLSCHEMA-instructie op. Daarom wordt een inline XSD-schema geretourneerd. Dit is het resultaat:

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

Let op het volgende uit de vorige query:

  • In het resultaat zijn <SalesOrderHeader> en <SalesOrderDetail> entiteitselementen. Daarom worden ze globaal gedeclareerd in het schema. Dat wil gezegd, de declaratie wordt weergegeven op het hoogste niveau in het <Schema> element.

  • De <SalesOrderID>, <ProductID>en <OrderQty> zijn geen entiteitselementen, omdat ze zijn toegewezen aan kolommen. De kolomgegevens worden geretourneerd als elementen in de XML, vanwege de ELEMENTS-instructie. Deze worden toegewezen aan lokale elementen van het complexe type entiteitselement. Als de ELEMENTS-instructie niet is opgegeven, worden de SalesOrderID, ProductID en OrderQty waarden toegewezen aan lokale kenmerken van het complexe type van het bijbehorende entiteitselement.

Conflicterende kenmerkna(a)m(en)

De volgende discussie is gebaseerd op de tabellen CustOrder en CustOrderDetail. Als u de volgende voorbeelden wilt testen, maakt u deze tabellen en voegt u uw eigen voorbeeldgegevens toe:

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

In FOR XML wordt dezelfde naam soms gebruikt om verschillende eigenschappen, kenmerken aan te geven. Met de volgende kenmerkgerichte RAW-modusquery worden bijvoorbeeld twee kenmerken gegenereerd met dezelfde naam, OrderID. Dit veroorzaakt een fout.

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

Omdat het echter acceptabel is om twee elementen met dezelfde naam te hebben, kunt u het probleem elimineren door de ELEMENTS-instructie toe te voegen:

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

Dit is het resultaat. Opmerking in het inline XSD-schema is het OrderID-element twee keer gedefinieerd. Een van de declaraties heeft minOccurs ingesteld op 0, die overeenkomt met de Order-id uit de tabel CustOrderDetail en de tweede wordt toegewezen aan de primaire sleutelkolom OrderID van de CustOrder-tabel waarbij minOccurs standaard 1 is.

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

Elementnaam botst

In FOR XML kan dezelfde naam worden gebruikt om twee subelementen aan te geven. Met de volgende query worden bijvoorbeeld de waarden ListPrice en DealerPrice van producten opgehaald, maar de query geeft dezelfde alias, Price, op voor deze twee kolommen. Daarom bevat de resulterende rijenset twee kolommen met dezelfde naam.

Case 1: Beide subelementen zijn niet-sleutelkolommen van hetzelfde type en kunnen NULL zijn

In de volgende query zijn beide subelementen niet-sleutelkolommen van hetzelfde type en kunnen ze NULL zijn.

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;

Dit is de bijbehorende XML die is gegenereerd. Er wordt slechts een fractie van de inline XSD weergegeven:

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

Let op het volgende in het inline XSD-schema:

  • Zowel ListPrice als DealerPrice zijn van hetzelfde type, moneyen beide kunnen NULL in de tabel zijn. Daarom, omdat ze mogelijk niet worden geretourneerd in de resulterende XML, is er slechts één <Price> onderliggend element in de complexe typedeclaratie van het <row>-element met minOccurs=0 en maxOccurs=2.

  • Omdat de DealerPrice waarde NULL in de tabel is, wordt alleen ListPrice geretourneerd als een <Price> element. Als u de parameter XSINIL toevoegt aan de ELEMENTS-instructie, ontvangt u beide elementen waarvan de xsi:nil waarde is ingesteld op TRUE voor het<Price> element dat overeenkomt met DealerPrice. U ontvangt ook twee <Price> kindelementen in de <row> complexe typedefinitie in het inline XSD-schema, waarbij het kenmerk nillable voor beide is ingesteld op true. Dit fragment is een gedeeltelijk resultaat:

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

Case 2: Één sleutel en één niet-sleutelkolom van hetzelfde type

De volgende query illustreert één sleutel en één niet-sleutelkolom van hetzelfde type.

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

De volgende query voor tabel T- geeft dezelfde alias op voor Col1 en Col2, waarbij Col1 een primaire sleutel is en niet null kan zijn en Col2 null kan zijn. Hiermee worden twee broederelementen gegenereerd die kinderen zijn van het <row>-element.

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

Dit is het resultaat. Alleen een fragment van het INLINE XSD-schema wordt weergegeven.

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

In het inline XSD-schema ziet u dat het element <Col> dat overeenkomt met de kolom2 minOccurs op 0 is ingesteld.

Case 3: Beide elementen van verschillende typen en bijbehorende kolommen kunnen NULL zijn

De volgende query wordt opgegeven voor de voorbeeldtabel die wordt weergegeven in geval 2:

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

In de volgende query krijgen Col2 en Col3 dezelfde aliassen. Hiermee worden twee gelijkwaardige elementen gegenereerd die dezelfde naam hebben en beide kinderen zijn van het <raw> element in het resultaat. Beide kolommen zijn van verschillende typen en beide kunnen NULL zijn. Dit is het resultaat. Er wordt alleen een gedeeltelijk XSD-schema inline weergegeven.

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

Let op het volgende in het inline XSD-schema:

  • Omdat zowel Col2 als Col3 NULL kunnen zijn, geeft de declaratie van het <Col>-element de minOccurs op als 0 en maxOccurs als 2.

  • Omdat zowel de <Col> elementen broers en zussen zijn, is er één elementdeclaratie in het schema. Omdat beide elementen ook van verschillende typen zijn, hoewel beide eenvoudige typen zijn, is het type element in het schema xsd:anySimpleType. In het resultaat wordt elk exemplaartype geïdentificeerd door het kenmerk xsi:type.

  • In het resultaat verwijst elk exemplaar van het <Col> element naar het exemplaartype met behulp van het kenmerk xsi:type.