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