Dela via


XML-konstruktion (XQuery)

gäller för:SQL Server

I XQuery kan du använda direkt och beräknade konstruktorer för att konstruera XML-strukturer i en fråga.

Not

Det finns ingen skillnad mellan de direkta och beräknade konstruktorerna.

Använda direktkonstruktorer

När du använder direktkonstruktorer anger du XML-liknande syntax när du skapar XML. Följande exempel illustrerar XML-konstruktion av direktkonstruktorerna.

Skapa element

När du använder XML-noteringar kan du skapa element. I följande exempel används det direkta elementkonstruktoruttrycket och ett <ProductModel> element skapas. Det konstruerade elementet har tre underordnade element

  • En textnod.

  • Två elementnoder och <Summary><Features>.

    • Elementet <Summary> har en underordnad textnod vars värde är "Some description".

    • Elementet <Features> har underordnade elementnoder, <Color>, <Weight>och <Warranty>. Var och en av dessa noder har en underordnad textnod och har värdena Red, 25, 2 years parts and laborrespektive .

DECLARE @x AS XML;

SET @x = '';

SELECT @x.query('<ProductModel ProductModelID="111">;
This is product model catalog description.
<Summary>Some description</Summary>
<Features>
  <Color>Red</Color>
  <Weight>25</Weight>
  <Warranty>2 years parts and labor</Warranty>
</Features></ProductModel>');

Här är den resulterande XML:en:

<ProductModel ProductModelID="111">
  This is product model catalog description.
  <Summary>Some description</Summary>
  <Features>
    <Color>Red</Color>
    <Weight>25</Weight>
    <Warranty>2 years parts and labor</Warranty>
  </Features>
</ProductModel>

Även om det är användbart att konstruera element från konstanta uttryck, vilket visas i det här exemplet, är den sanna kraften i den här XQuery-språkfunktionen möjligheten att konstruera XML som dynamiskt extraherar data från en databas. Du kan använda klammerparenteser för att ange frågeuttryck. I den resulterande XML-koden ersätts uttrycket med dess värde. Följande fråga skapar till exempel ett <NewRoot> element med ett underordnat element (<e>). Värdet för elementet <e> beräknas genom att ange ett sökvägsuttryck inuti klammerparenteser ("{ ... }").

DECLARE @x AS XML;

SET @x = '<root>5</root>';

SELECT @x.query('<NewRoot><e> { /root } </e></NewRoot>');

Klammerparenteserna fungerar som kontextväxlingstoken och växlar frågan från XML-konstruktion till frågeutvärdering. I det här fallet utvärderas XQuery-sökvägsuttrycket inuti klammerparenteserna, /root, och resultatet ersätts med det.

Här är resultatet:

<NewRoot>
  <e>
    <root>5</root>
  </e>
</NewRoot>

Följande fråga liknar den föregående. Uttrycket i klammerparenteserna anger data() dock funktionen för att hämta elementets <root> atomiska värde och tilldelar det till det konstruerade elementet , <e>.

DECLARE @x AS XML;
SET @x = '<root>5</root>';

DECLARE @y AS XML;
SET @y = (SELECT @x.query('
                           <NewRoot>
                             <e> { data(/root) } </e>
                           </NewRoot>'));

SELECT @y;

Här är resultatet:

<NewRoot>
  <e>5</e>
</NewRoot>

Om du vill använda klammerparenteserna som en del av texten i stället för kontextväxlingstoken kan du undvika dem som "}}" eller "{{", som du ser i det här exemplet:

DECLARE @x AS XML;
SET @x = '<root>5</root>';

DECLARE @y AS XML;
SET @y = (SELECT @x.query('
<NewRoot> Hello, I can use {{ and  }} as part of my text</NewRoot>'));

SELECT @y;

Här är resultatet:

<NewRoot> Hello, I can use { and  } as part of my text</NewRoot>

Följande fråga är ett annat exempel på hur du skapar element med hjälp av konstruktorn för direktelement. Dessutom hämtas värdet för elementet <FirstLocation> genom att uttrycket körs i klammerparenteserna. Frågeuttrycket returnerar tillverkningsstegen på den första arbetsställeplatsen från kolumnen Instruktioner i tabellen Production.ProductModel.

SELECT Instructions.query('
    declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
        <FirstLocation>
           { /AWMI:root/AWMI:Location[1]/AWMI:step }
        </FirstLocation>
') AS Result
FROM Production.ProductModel
WHERE ProductModelID = 7;

Här är resultatet:

<FirstLocation>
  <AWMI:step xmlns:AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions">
      Insert <AWMI:material>aluminum sheet MS-2341</AWMI:material> into the <AWMI:tool>T-85A framing tool</AWMI:tool>.
  </AWMI:step>
  <AWMI:step xmlns:AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions">
      Attach <AWMI:tool>Trim Jig TJ-26</AWMI:tool> to the upper and lower right corners of the aluminum sheet.
  </AWMI:step>
   ...
</FirstLocation>

Elementinnehåll i XML-konstruktion

I följande exempel visas hur uttrycken konstruerar elementinnehåll med hjälp av konstruktorn för direktelement. I följande exempel anger konstruktorn för direktelement ett uttryck. För det här uttrycket skapas en textnod i den resulterande XML-koden.

DECLARE @x AS XML;
SET @x = '
<root>
  <step>This is step 1</step>
  <step>This is step 2</step>
  <step>This is step 3</step>
</root>';

SELECT @x.query('
<result>
 { for $i in /root[1]/step
    return string($i)
 }
</result>');

Den atomiska värdesekvensen som är resultatet av uttrycksutvärderingen läggs till i textnoden med ett blanksteg som läggs till mellan de intilliggande atomiska värdena, vilket visas i resultatet. Det konstruerade elementet har ett underordnat element. Det här är en textnod som innehåller det värde som visas i resultatet.

<result>This is step 1 This is step 2 This is step 3</result>

I stället för ett uttryck, om du anger tre separata uttryck som genererar tre textnoder, sammanfogas de intilliggande textnoderna till en enda textnod, genom sammanfogning, i den resulterande XML-koden.

DECLARE @x AS XML;
SET @x = '
<root>
  <step>This is step 1</step>
  <step>This is step 2</step>
  <step>This is step 3</step>
</root>';

SELECT @x.query('
<result>
 { string(/root[1]/step[1]) }
 { string(/root[1]/step[2]) }
 { string(/root[1]/step[3]) }
</result>');

Den konstruerade elementnoden har en underordnad. Det här är en textnod som innehåller det värde som visas i resultatet.

<result>This is step 1This is step 2This is step 3</result>

Skapa attribut

När du skapar element med hjälp av konstruktorn för direktelement kan du också ange attribut för elementet med hjälp av XML-liknande syntax, som du ser i det här exemplet:

DECLARE @x AS XML;
SET @x = '';

SELECT @x.query('<ProductModel ProductModelID="111">;
This is product model catalog description.
<Summary>Some description</Summary>
</ProductModel>');

Här är den resulterande XML:en:

<ProductModel ProductModelID="111">
  This is product model catalog description.
  <Summary>Some description</Summary>
</ProductModel>

Det konstruerade elementet <ProductModel> har ett ProductModelID-attribut och dessa underordnade noder:

  • En textnod This is product model catalog description.

  • En elementnod, <Summary>. Den här noden har en underordnad textnod, Some description.

När du skapar ett attribut kan du ange dess värde med ett uttryck i klammerparenteser. I det här fallet returneras resultatet av uttrycket som attributvärde.

I följande exempel data() är funktionen inte strikt obligatorisk. Eftersom du tilldelar uttrycksvärdet till ett attribut data() tillämpas implicit för att hämta det typgivna värdet för det angivna uttrycket.

DECLARE @x AS XML;
SET @x = '<root>5</root>';

DECLARE @y AS XML;
SET @y = (SELECT @x.query('<NewRoot attr="{ data(/root) }" ></NewRoot>'));

SELECT @y;

Här är resultatet:

<NewRoot attr="5" />

Följande är ett annat exempel där uttryck anges för attributkonstruktionen LocationID och SetupHrs. Dessa uttryck utvärderas mot XML i kolumnen Instruktion. Uttryckets typerade värde tilldelas attributen.

SELECT Instructions.query('
    declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
        <FirstLocation
         LocationID="{ (/AWMI:root/AWMI:Location[1]/@LocationID)[1] }"
         SetupHrs = "{ (/AWMI:root/AWMI:Location[1]/@SetupHours)[1] }" >
           { /AWMI:root/AWMI:Location[1]/AWMI:step }
        </FirstLocation>
') AS Result
FROM Production.ProductModel
WHERE ProductModelID = 7;

Här är det partiella resultatet:

<FirstLocation LocationID="10" SetupHours="0.5" >
  <AWMI:step ...
  </AWMI:step>
  ...
</FirstLocation>

Implementeringsbegränsningar

Det här är begränsningarna:

  • Flera eller blandade attribututtryck (sträng- och XQuery-uttryck) stöds inte. Som du till exempel ser i följande fråga skapar du XML där Item är en konstant och värdet 5 hämtas genom att utvärdera ett frågeuttryck:

    <a attr="Item 5" />
    

    Följande fråga returnerar ett fel eftersom du blandar konstant sträng med ett uttryck ({/x}) och detta stöds inte:

    DECLARE @x AS XML;
    SET @x = '<x>5</x>';
    
    SELECT @x.query('<a attr="Item {/x}"/>');
    

    I det här fallet har du följande alternativ:

    • Skapa attributvärdet genom sammanfogning av två atomiska värden. Dessa atomiska värden serialiseras till attributvärdet med ett blanksteg mellan atomvärdena:

      SELECT @x.query('<a attr="{''Item'', data(/x)}"/>');
      

      Här är resultatet:

      <a attr="Item 5" />
      
    • Använd funktionen concat för att sammanfoga de två strängargumenten till det resulterande attributvärdet:

      SELECT @x.query('<a attr="{concat(''Item'', /x[1])}"/>');
      

      I det här fallet läggs inget utrymme till mellan de två strängvärdena. Om du vill ha ett blanksteg mellan de två värdena måste du uttryckligen ange det.

      Här är resultatet:

      <a attr="Item5" />
      
  • Flera uttryck som ett attributvärde stöds inte. Följande fråga returnerar till exempel ett fel:

    DECLARE @x AS XML;
    SET @x = '<x>5</x>';
    
    SELECT @x.query('<a attr="{/x}{/x}"/>');
    
  • Heterogena sekvenser stöds inte. Alla försök att tilldela en heterogen sekvens som ett attributvärde returnerar ett fel, enligt följande exempel. I det här exemplet anges en heterogen sekvens, en sträng "Item" och ett element <x>som attributvärde:

    DECLARE @x AS XML;
    SET @x = '<x>5</x>';
    
    SELECT @x.query('<a attr="{''Item'', /x }" />');
    

    Om du använder data() funktionen fungerar frågan eftersom den hämtar det atomiska värdet för uttrycket , /xsom sammanfogas med strängen. Följande är en sekvens med atomiska värden:

    SELECT @x.query('<a attr="{''Item'', data(/x)}"/>');
    

    Här är resultatet:

    <a attr="Item 5" />
    
  • Attributnodordningen framtvingas under serialiseringen i stället för vid kontroll av statisk typ. Följande fråga misslyckas till exempel eftersom den försöker lägga till ett attribut efter en nod utan attribut.

    SELECT CONVERT (XML, '').query('
        element x { attribute att { "pass" }, element y { "Element text" }, attribute att2 { "fail" } }
        ');
    GO
    

    Föregående fråga returnerar följande fel:

    XML well-formedness check: Attribute cannot appear outside of element declaration. Rewrite your XQuery so it returns well-formed XML.
    

Lägga till namnområden

När du skapar XML med hjälp av direktkonstruktorerna kan de konstruerade element- och attributnamnen kvalificeras med hjälp av ett namnområdesprefix. Du kan binda prefixet till namnområdet på följande sätt:

  • Genom att använda ett namnområdesdeklarationsattribut.
  • Genom att WITH XMLNAMESPACES använda -satsen.
  • I XQuery-prologen.

Använda ett namnområdesdeklarationsattribut för att lägga till namnområden

I följande exempel används ett namnområdesdeklarationsattribut i konstruktionen av elementet <a> för att deklarera ett standardnamnområde. Konstruktionen av det underordnade elementet <b> ångrar deklarationen för standardnamnområdet som deklarerats i det överordnade elementet.

DECLARE @x AS XML;
SET @x = '<x>5</x>';

SELECT @x.query('
  <a xmlns="a">
    <b xmlns=""/>
  </a>');

Här är resultatet:

<a xmlns="a">
  <b xmlns="" />
</a>

Du kan tilldela ett prefix till namnområdet. Prefixet anges i konstruktionen av elementet <a>.

DECLARE @x AS XML;
SET @x = '<x>5</x>';

SELECT @x.query('
  <x:a xmlns:x="a">
    <b/>
  </x:a>');

Här är resultatet:

<x:a xmlns:x="a">
  <b />
</x:a>

Du kan avregistrera ett standardnamnområde i XML-konstruktionen, men du kan inte avregistrera ett namnområdesprefix. Följande fråga returnerar ett fel eftersom du inte kan av deklarera ett prefix enligt beskrivningen i konstruktionen av elementet <b>.

DECLARE @x AS XML;
SET @x = '<x>5</x>';

SELECT @x.query('
  <x:a xmlns:x="a">
    <b xmlns:x=""/>
  </x:a>');

Det nyligen skapade namnområdet är tillgängligt att använda i frågan. Följande fråga deklarerar till exempel ett namnområde när elementet skapas, <FirstLocation>, och anger prefixet i uttrycken för attributvärdena LocationID och SetupHrs.

SELECT Instructions.query('
        <FirstLocation xmlns:AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions"
         LocationID="{ (/AWMI:root/AWMI:Location[1]/@LocationID)[1] }"
         SetupHrs = "{ (/AWMI:root/AWMI:Location[1]/@SetupHours)[1] }" >
           { /AWMI:root/AWMI:Location[1]/AWMI:step }
        </FirstLocation>
') AS Result
FROM Production.ProductModel
WHERE ProductModelID = 7;

Om du skapar ett nytt namnområdesprefix på det här sättet åsidosätts alla befintliga namnområdesdeklarationer för det här prefixet. Till exempel åsidosättas namnområdesdeklarationen , AWMI="https://someURI"i frågeprologen av namnområdesdeklarationen i elementet <FirstLocation> .

SELECT Instructions.query('
declare namespace AWMI="https://someURI";
        <FirstLocation xmlns:AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions"
         LocationID="{ (/AWMI:root/AWMI:Location[1]/@LocationID)[1] }"
         SetupHrs = "{ (/AWMI:root/AWMI:Location[1]/@SetupHours)[1] }" >
           { /AWMI:root/AWMI:Location[1]/AWMI:step }
        </FirstLocation>
') AS Result
FROM Production.ProductModel
WHERE ProductModelID = 7;

Använd en prolog för att lägga till namnområden

Det här exemplet illustrerar hur namnområden kan läggas till i den konstruerade XML-koden. Ett standardnamnområde deklareras i frågeprologen.

DECLARE @x AS XML;
SET @x = '<x>5</x>';

SELECT @x.query('
           declare default element namespace "a";
            <a><b xmlns=""/></a>');

I konstruktionen av elementet <b>anges attributet för namnområdesdeklaration med en tom sträng som värde. Detta av deklarerar standardnamnområdet som deklareras i det överordnade objektet.

Här är resultatet:

<a xmlns="a">
  <b xmlns="" />
</a>

XML-konstruktion och hantering av tomt utrymme

Elementinnehållet i XML-konstruktionen kan innehålla blankstegstecken. Dessa tecken hanteras på följande sätt:

  • Blankstegstecken i namnområdes-URI:er behandlas som XSD-typen anyURI. Mer specifikt är det så här de hanteras:

    • Eventuella blankstegstecken i början och slutet trimmas.
    • Interna blankstegsteckenvärden komprimeras till ett enda blanksteg
  • Radmatningstecken i attributinnehållet ersätts av blanksteg. Alla andra blankstegstecken finns kvar som de är.

  • Det tomma utrymmet inuti element bevaras.

I följande exempel visas hantering av blanksteg i XML-konstruktion:

-- line feed is replaced by space.
DECLARE @x AS XML;
SET @x = '';

SELECT @x.query('

declare namespace myNS="   https://
 abc/
xyz

";
<test attr="    my
test   attr
value    " >

<a>

This     is  a

test

</a>
</test>
') AS XML_Result;

Här är resultatet:

-- result
<test attr="<test attr="    my test   attr  value    "><a>

This     is  a

test

</a></test>
"><a>

This     is  a

test

</a></test>

Andra direkta XML-konstruktorer

Konstruktorerna för bearbetning av instruktioner och XML-kommentarer använder samma syntax som motsvarande XML-konstruktionssyntax. Beräknade konstruktorer för textnoder stöds också, men används främst i XML DML för att konstruera textnoder.

Not

Ett exempel på hur du använder en explicit textnodkonstruktor finns i det specifika exemplet i Insert (XML DML).

I följande fråga innehåller den konstruerade XML-koden ett element, två attribut, en kommentar och en bearbetningsinstruktion. Ett kommatecken används före <FirstLocation>, eftersom en sekvens skapas.

SELECT Instructions.query('
  declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
   <?myProcessingInstr abc="value" ?>,
   <FirstLocation
        WorkCtrID = "{ (/AWMI:root/AWMI:Location[1]/@LocationID)[1] }"
        SetupHrs = "{ (/AWMI:root/AWMI:Location[1]/@SetupHours)[1] }" >
       <!-- some comment -->
       <?myPI some processing instructions ?>
       { (/AWMI:root/AWMI:Location[1]/AWMI:step) }
    </FirstLocation>
') AS Result
FROM Production.ProductModel
WHERE ProductModelID = 7;

Här är det partiella resultatet:

<?myProcessingInstr abc="value" ?>
<FirstLocation WorkCtrID="10" SetupHrs="0.5">
  <!-- some comment -->
  <?myPI some processing instructions ?>
  <AWMI:step xmlns:AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions">I
  nsert <AWMI:material>aluminum sheet MS-2341</AWMI:material> into the <AWMI:tool>T-85A framing tool</AWMI:tool>.
  </AWMI:step>
    ...
</FirstLocation>

Använda beräknade konstruktorer

I det här fallet anger du de nyckelord som identifierar vilken typ av nod du vill skapa. Endast följande nyckelord stöds:

  • element
  • attribut
  • SMS

För element- och attributnoder följs dessa nyckelord av nodnamn och även av uttrycket, omgivet av klammerparenteser, som genererar innehållet för noden. I följande exempel skapar du den här XML:en:

<root>
  <ProductModel PID="5">Some text <summary>Some Summary</summary></ProductModel>
</root>

Här är frågan som använder beräknade konstruktorer genererar XML:

DECLARE @x AS XML;
SET @x = '';

SELECT @x.query('element root
               {
                  element ProductModel
     {
attribute PID { 5 },
text{"Some text "},
    element summary { "Some Summary" }
 }
               } ');

Uttrycket som genererar nodinnehållet kan ange ett frågeuttryck.

DECLARE @x AS XML;
SET @x = '<a attr="5"><b>some summary</b></a>';

SELECT @x.query('element root
               {
                  element ProductModel
     {
attribute PID { /a/@attr },
text{"Some text "},
    element summary { /a/b }
 }
               } ');

Med det beräknade elementet och attributkonstruktorerna, enligt definitionen i XQuery-specifikationen, kan du beräkna nodnamnen. När du använder direktkonstruktorer i SQL Server måste nodnamnen, till exempel element och attribut, anges som konstanta literaler. Därför finns det ingen skillnad i direkta konstruktorer och beräknade konstruktorer för element och attribut.

I följande exempel hämtas innehållet för de konstruerade noderna från XML-tillverkningsinstruktionerna som lagras i kolumnen Instruktioner i xml- datatyp i tabellen ProductModel.

SELECT Instructions.query('
  declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
   element FirstLocation
     {
        attribute LocationID { (/AWMI:root/AWMI:Location[1]/@LocationID)[1] },
        element   AllTheSteps { /AWMI:root/AWMI:Location[1]/AWMI:step }
     }
') AS Result
FROM Production.ProductModel
WHERE ProductModelID = 7;

Här är det partiella resultatet:

<FirstLocation LocationID="10">
  <AllTheSteps>
    <AWMI:step> ... </AWMI:step>
    <AWMI:step> ... </AWMI:step>
    ...
  </AllTheSteps>
</FirstLocation>

Andra implementeringsbegränsningar

Konstruktorer för beräknade attribut kan inte användas för att deklarera ett nytt namnområde. Dessutom stöds inte följande beräknade konstruktorer i SQL Server:

  • Konstruktorer för beräknade dokumentnoder
  • Instruktionskonstruktorer för beräknad bearbetning
  • Beräknade kommentarskonstruktorer