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 direkta och beräknade konstruktorer.

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.

Konstruera element

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

  • En textnod.

  • Två elementnoder, <Sammanfattning> och <funktioner>.

    • Elementet <Sammanfattning> har en underordnad textnod vars värde är "Viss beskrivning".

    • Elementet <Funktioner> har underordnade elementnoder, <Color>, <Weight>och <Warranty>. Var och en av dessa noder har en underordnad textnod och har värdena Röd, 25, 2 års delar respektive arbete.

declare @x 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>')  
  

Det 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 konstruerar 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 i klammerparenteser ("{ ... }").

DECLARE @x 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.

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 dock funktionen data() för att hämta atomvärdet för <root>-elementet och tilldelar det till det konstruerade elementet <e>.

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

Det 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 xml;  
SET @x='<root>5</root>';  
DECLARE @y xml;  
SET @y = (SELECT @x.query('  
<NewRoot> Hello, I can use {{ and  }} as part of my text</NewRoot>'));  
SELECT @y;  

Det 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 det <FirstLocation> elementet genom att köra uttrycket 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;  

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

Konstruera attribut

När du skapar element med hjälp av direktelementkonstruktorn 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 xml;  
set @x='';  
select @x.query('<ProductModel ProductModelID="111">;  
This is product model catalog description.  
<Summary>Some description</Summary>  
</ProductModel>')  

Det 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 följande 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 krävs inte funktionen data() strikt. Eftersom du tilldelar uttrycksvärdet till ett attribut används data() implicit för att hämta det angivna uttryckets typade värde.

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

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

Detta ä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 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)}"/>' )   
      

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

      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 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, vilket visas i följande exempel. I det här exemplet anges en heterogen sekvens, en sträng "Item" och ett element <x>, som attributvärdet:

    DECLARE @x xml  
    SET @x ='<x>5</x>'  
    select @x.query( '<a attr="{''Item'', /x }" />')  
    

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

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

    Det 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  
    

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

  • Med hjälp av WITH XMLNAMESPACES-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 xml  
set @x ='<x>5</x>'  
select @x.query( '  
  <a xmlns="a">  
    <b xmlns=""/>  
  </a>' )   

Det 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 xml  
set @x ='<x>5</x>'  
select @x.query( '  
  <x:a xmlns:x="a">  
    <b/>  
  </x:a>' )  

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

Observera att 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 <FirstLocation>-elementet.

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ända 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 xml  
set @x ='<x>5</x>'  
select @x.query( '  
           declare default element namespace "a";  
            <a><b xmlns=""/></a>' )  

Observera att i konstruktionen av elementet <b>anges namnområdesdeklarationsattributet med en tom sträng som värde. Detta av deklarerar standardnamnområdet som deklareras i det överordnade objektet.

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

Det 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 Direct XML-konstruktorer

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

Obs 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. Observera att 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;  
  

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

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

declare @x 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 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 }  
 }  
               } ')  

Observera att de beräknade element- och attributkonstruktorerna, enligt definitionen i XQuery-specifikationen, gör att du kan 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  

Detta är det partiella resultatet:

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

Ytterligare implementeringsbegränsningar

Beräkningsattributkonstruktorer 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

Se även

XQuery-uttryck