Condividi tramite


Costruzione di strutture XML (XQuery)

Si applica a:SQL Server

In XQuery è possibile usare i costruttori diretti e calcolati per costruire strutture XML all'interno di una query.

Nota

Non esiste alcuna differenza tra i costruttori diretti e calcolati .

Utilizzo dei costruttori diretti

Quando si utilizzano i costruttori diretti, nella costruzione delle strutture XML si specifica una sintassi in stile XML. Negli esempi seguenti viene illustrata la costruzione delle strutture XML mediante i costruttori diretti.

Costruzione di elementi

Con le annotazioni XML è possibile costruire elementi. Nell'esempio seguente viene utilizzata l'espressione del costruttore dell'elemento diretto e viene creato un <elemento ProductModel> . L'elemento costruito dispone di tre elementi figlio

  • Un nodo di testo.

  • Due nodi elemento, <Riepilogo> e <Funzionalità>.

    • L'elemento <Summary> ha un elemento figlio del nodo di testo il cui valore è "Some description".

    • L'elemento <Features> include tre elementi figlio, <Color>, <Weight> e <Warranty>. Ognuno di questi nodi ha un nodo di testo figlio. I valori dei nodi sono rispettivamente "Red", "25" e "2 years parts and labor".

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

Codice XML risultante:

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

Anche se la costruzione di elementi da espressioni costanti, come illustrato in questo esempio, può risultare utile, il punto forte di questa caratteristica del linguaggio XQuery è costituito dalla possibilità di costruire strutture XML che estraggono i dati da un database in modo dinamico. È possibile utilizzare le parentesi graffe per specificare le espressioni di query. Nel codice XML risultante l'espressione viene sostituita dal relativo valore. Ad esempio, la query seguente costruisce un <NewRoot> elemento con un elemento figlio (<e>). Il valore dell'elemento <e> viene calcolato specificando un'espressione di percorso all'interno di parentesi graffe ("{ ... }").

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

La parentesi fungono da token di cambio del contesto e attivano il passaggio dalla modalità di costruzione di strutture XML alla modalità di valutazione della query. In questo caso viene valutata l'espressione di percorso XQuery all'interno delle parentesi, /root e al suo posto vengono inseriti i relativi risultati.

Risultato:

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

La query successiva è simile alla precedente. Tuttavia, l'espressione tra parentesi graffe specifica la funzione data() per recuperare il valore atomico dell'elemento>root< e la assegna all'elemento costruito, . <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;  

Risultato:

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

Se si desidera utilizzare le parentesi graffe come parte del testo invece che come token di scambio del contesto, è necessario utilizzare la relativa sequenza di escape "}}" o "{{", come illustrato in questo esempio:

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;  

Risultato:

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

La query seguente è un altro esempio di creazione di elementi mediante il costruttore diretto di elementi. Inoltre, il valore dell'elemento <FirstLocation> viene ottenuto eseguendo l'espressione tra parentesi graffe. L'espressione della query restituisce le fasi di produzione nel primo centro di lavorazione dalla colonna Instructions della tabella 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;  

Risultato:

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

Contenuto dell'elemento nella costruzione di strutture XML

Nell'esempio seguente viene illustrato il funzionamento delle espressioni nella creazione del contenuto dell'elemento utilizzando il costruttore diretto di elementi. Nell'esempio seguente, il costruttore diretto di elementi specifica un'espressione. In base a questa espressione, nel codice XML risultante viene creato un nodo di testo.

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>');  
  

La sequenza di valori atomici risultante dalla valutazione dell'espressione viene aggiunta al nodo di testo con l'aggiunta di uno spazio fra i valori atomici adiacenti, come illustrato nel risultato. L'elemento creato ha un figlio, un nodo di testo contenente il valore mostrato nel risultato.

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

Se anziché una sola espressione si specificano tre espressioni separate che generano tre nodi di testo, nel codice XML risultante i nodi di testo adiacenti vengono uniti in un singolo nodo di testo, per concatenazione.

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>');  

Il nodo di elemento creato ha un figlio, un nodo di testo contenente il valore mostrato nel risultato.

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

Costruzione di attributi

Quando si costruiscono elementi utilizzando il costruttore diretto di elementi è possibile specificarne gli attributi utilizzando sintassi in stile XML, come illustrato nell'esempio seguente:

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

Codice XML risultante:

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

L'elemento <ProductModel> costruito ha un attributo ProductModelID e questi nodi figlio:

  • Un nodo di testo, This is product model catalog description.

  • Nodo elemento, <Summary>. Questo nodo ha un nodo di testo figlio, Some description.

Quando si costruisce un attributo è possibile specificarne il valore mediante un'espressione fra parentesi graffe. In questo caso, il valore dell'espressione viene restituito come valore dell'attributo.

Nell'esempio seguente la funzione data() non è strettamente necessaria. Poiché si assegna il valore dell'espressione a un attributo, data() viene applicato in modo implicito per recuperare il valore tipizzato dell'espressione specificata.

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

Risultato:

<NewRoot attr="5" />  

Di seguito viene riportato un altro esempio nel quale vengono specificate espressioni per la costruzione degli attributi LocationID e SetupHrs. Le espressioni vengono valutate in base al codice XML nella colonna Instruction. Il valore tipizzato dell'espressione viene assegnato agli attributi.

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;  

Risultato parziale:

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

Limitazioni di implementazione

Limitazioni:

  • Le espressioni di attributo multiple o miste (stringa ed espressione XQuery) non sono supportate. Ad esempio, come illustrato nella query seguente, si costruisce una struttura XML dove Item è una costante e il valore 5 viene ottenuto valutando un'espressione di query:

    <a attr="Item 5" />  
    

    La query seguente restituisce un errore, perché combina una stringa costante con un'espressione ({/x}) e ciò non è supportato:

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

    In questo caso sono disponibili le opzioni seguenti:

    • Formare il valore dell'attributo mediante la concatenazione di due valori atomici. Tali valori atomici vengono serializzati nel valore dell'attributo con uno spazio fra un valore e l'altro:

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

      Risultato:

      <a attr="Item 5" />  
      
    • Usare la funzione concat per concatenare i due argomenti stringa nel valore dell'attributo risultante:

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

      In questo caso, fra i due valori stringa non vengono aggiunti spazi. Se si desidera l'aggiunta di uno spazio fra i valori è necessario inserirlo esplicitamente.

      Risultato:

      <a attr="Item5" />  
      
  • Le espressioni multiple come valore di attributo non sono supportate. Ad esempio, la query seguente restituisce un errore:

    DECLARE @x xml  
    SET @x ='<x>5</x>'  
    SELECT @x.query( '<a attr="{/x}{/x}"/>' )  
    
  • Le sequenze eterogenee non sono supportate. Qualsiasi tentativo di assegnare una sequenza eterogenea come valore di attributo provocherà la restituzione di un errore, come illustrato nell'esempio seguente. In questo esempio, una sequenza eterogenea, una stringa "Item" e un elemento <x>, viene specificata come valore dell'attributo:

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

    Se si applica la funzione data(), la query funziona perché recupera il valore atomico dell'espressione , /xche viene concatenato con la stringa. Quella che segue è una sequenza di valori atomici:

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

    Risultato:

    <a attr="Item 5" />  
    
  • L'ordine del nodo attributo viene applicato durante la serializzazione anziché durante il controllo dei tipi statici. Ad esempio, la query seguente ha esito negativo poiché tenta di aggiungere un attributo dopo un nodo non attributo.

    select convert(xml, '').query('  
    element x { attribute att { "pass" }, element y { "Element text" }, attribute att2 { "fail" } }  
    ')  
    go  
    

    La query precedente restituisce l'errore seguente:

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

Aggiunta degli spazi dei nomi

Quando si costruiscono strutture XML utilizzando i costruttori diretti, è possibile qualificare i nomi degli elementi e degli attributi costruiti mediante un prefisso di spazio dei nomi. È possibile associare il prefisso allo spazio dei nomi come indicato di seguito:

  • Utilizzando un attributo di dichiarazione dello spazio dei nomi.

  • Utilizzando la clausola WITH XMLNAMESPACES.

  • Nel prologo della XQuery.

Utilizzo di un attributo di dichiarazione dello spazio dei nomi per l'aggiunta degli spazi dei nomi

Nell'esempio seguente viene usato un attributo di dichiarazione dello spazio dei nomi nella costruzione dell'elemento <a> per dichiarare uno spazio dei nomi predefinito. La costruzione dell'elemento <b> figlio annulla la dichiarazione dello spazio dei nomi predefinito dichiarato nell'elemento padre.

declare @x xml  
set @x ='<x>5</x>'  
select @x.query( '  
  <a xmlns="a">  
    <b xmlns=""/>  
  </a>' )   

Risultato:

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

È possibile assegnare allo spazio dei nomi un prefisso, Il prefisso viene specificato nella costruzione dell'elemento <a>.

declare @x xml  
set @x ='<x>5</x>'  
select @x.query( '  
  <x:a xmlns:x="a">  
    <b/>  
  </x:a>' )  

Risultato:

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

È possibile annullare la dichiarazione di uno spazio dei nomi predefinito nella costruzione di strutture XML, ma non di un prefisso di spazio dei nomi. La query seguente restituisce un errore perché non è possibile dichiarare un prefisso come specificato nella costruzione dell'elemento <b>.

declare @x xml  
set @x ='<x>5</x>'  
select @x.query( '  
  <x:a xmlns:x="a">  
    <b xmlns:x=""/>  
  </x:a>' )  

Il nuovo spazio dei nomi costruito è disponibile per l'utilizzo all'interno della query. Ad esempio, la query seguente dichiara uno spazio dei nomi nella costruzione dell'elemento , <FirstLocation>e specifica il prefisso nelle espressioni per i valori dell'attributo LocationID e 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  

Si noti che un nuovo prefisso di spazio dei nomi creato in questo modo sostituirà le dichiarazioni dello spazio dei nomi preesistenti per il prefisso. Ad esempio, la dichiarazione dello spazio dei nomi , AWMI="https://someURI"nel prologo della query viene sottoposta a override dalla dichiarazione dello spazio dei nomi nell'elementoFirstLocation<> .

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  

Utilizzo di un prologo per l'aggiunta degli spazi dei nomi

In questo esempio viene illustrata l'aggiunta degli spazi dei nomi alla struttura XML costruita. Nel prologo della query viene dichiarato uno spazio dei nomi predefinito.

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

Si noti che nella costruzione dell'elemento <b>, l'attributo di dichiarazione dello spazio dei nomi viene specificato con una stringa vuota come valore. In questo modo la dichiarazione dello spazio dei nomi predefinito dichiarato nel padre viene annullata.

Risultato:

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

Costruzione di strutture XML e gestione degli spazi vuoti

Il contenuto dell'elemento nella costruzione di strutture XML può includere spazi vuoti. Tali spazi vengono gestiti come descritto di seguito:

  • Gli spazi vuoti negli URI dello spazio dei nomi vengono considerati come qualsiasi URI di tipo XSD. Nello specifico:

    • Gli spazi vuoti iniziali e finali vengono rimossi.

    • Gli spazi vuoti all'interno delle istruzioni vengono compressi in un unico spazio

  • I caratteri di avanzamento riga all'interno del contenuto dell'attributo vengono sostituiti con spazi. Tutti gli altri spazi vuoti restano invariati.

  • Lo spazio vuoto all'interno degli elementi viene mantenuto.

Nell'esempio seguente viene illustrata la gestione degli spazi vuoti nella costruzione di strutture XML:

-- line feed is repaced 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  
  

Risultato:

-- result  
<test attr="<test attr="    my test   attr  value    "><a>  
  
This     is  a  
  
test  
  
</a></test>  
"><a>  
  
This     is  a  
  
test  
  
</a></test>  

Altri costruttori XML diretti

I costruttori per le istruzioni di elaborazione e i commenti XML utilizzano la stessa sintassi del costrutto XML corrispondente. Sono inoltre supportati costruttori calcolati per i nodi di testo, ma vengono utilizzati principalmente nel linguaggio XML DML per la costruzione di nodi di testo.

Nota Per un esempio di utilizzo di un costruttore esplicito di nodi di testo, vedere l'esempio specifico in insert (XML DML).

Nella query seguente il costrutto XML include un elemento, due attributi, un commento e un'istruzione di elaborazione. Si noti che una virgola viene usata prima di <FirstLocation>, perché viene costruita una sequenza.

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;  
  

Risultato parziale:

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

Utilizzo dei costruttori calcolati

. In questo caso si specificano le parole chiave che identificano il tipo di nodo da costruire. Sono supportate solo le parole chiave seguenti:

  • element

  • attribute

  • testo

Per i nodi elemento e attributo, le parole chiave sono seguite dal nome del nodo e dall'espressione, racchiusa fra parentesi, che genera il contenuto del nodo. Nell'esempio seguente si costruisce il codice XML successivo:

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

Di seguito è riportata la query che utilizza i costruttori calcolati per generare il codice XML:

declare @x xml  
set @x=''  
select @x.query('element root   
               {   
                  element ProductModel  
     {  
attribute PID { 5 },  
text{"Some text "},  
    element summary { "Some Summary" }  
 }  
               } ')  
  

L'espressione che genera il contenuto del nodo può specificare un'espressione di query.

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 }  
 }  
               } ')  

Si noti che i costruttori di nodi e attributi calcolati, come definiti nella specifica XQuery, consentono il calcolo dei nomi dei nodi. Quando si usano costruttori diretti in SQL Server, i nomi dei nodi, ad esempio elemento e attributo, devono essere specificati come valori letterali costanti. Non esistono pertanto differenze fra costruttori di elementi e attributi diretti e calcolati.

Nell'esempio seguente il contenuto per i nodi costruiti viene ottenuto dalle istruzioni di produzione XML archiviate nella colonna Istruzioni del tipo di dati xml nella tabella 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  

Risultato parziale:

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

Ulteriori limitazioni di implementazione

I costruttori di attributi calcolati non possono essere utilizzati per dichiarare un nuovo spazio dei nomi. Inoltre, i costruttori calcolati seguenti non sono supportati in SQL Server:

  • Costruttori di nodi di documento calcolati

  • Costruttori di istruzioni di elaborazione calcolate

  • Costruttori di commenti calcolati

Vedi anche

Espressioni XQuery