Share via


Utilizzo della modalità EXPLICIT

Come illustrato nell'argomento relativo alla creazione di XML utilizzando FOR XML, le modalità RAW e AUTO forniscono scarso controllo sulla forma del codice XML generato dai risultati della query. La modalità EXPLICIT tuttavia offre maggiore flessibilità nella generazione del codice XML desiderato dal risultato di una query.

La query in modalità EXPLICIT deve essere formulata in modo tale che le informazioni aggiuntive relative al codice XML, ad esempio la nidificazione desiderata vengano specificate in modo esplicito nell'ambito della query stessa. In base al codice XML desiderato, la formulazione di query in modalità EXPLICIT può essere un'operazione complessa. L'utilizzo della modalità PATH con nidificazione è un'alternativa più semplice alla scrittura di query in modalità EXPLICIT.

Poiché in modalità EXPLICIT si descrive il codice XML desiderato nell'ambito della query, è necessario assicurarsi che il codice XML generato sia in formato corretto e valido.

Elaborazione dei set di righe in modalità EXPLICIT

La modalità EXPLICIT converte il set di righe risultante dall'esecuzione della query in un documento XML. Affinché la modalità EXPLICIT generi il documento XML, è necessario che il set di righe abbia un formato specifico. A questo scopo è necessario formulare la query SELECT in modo tale che restituisca il set di righe, la tabella universale, con un formato specifico in modo che la logica di elaborazione possa creare il codice XML desiderato.

Innanzitutto, la query deve produrre le due colonne di metadati seguenti:

  • La prima colonna deve contenere il numero di tag e il tipo Integer dell'elemento corrente. Il nome della colonna deve essere Tag. La query deve fornire un numero di tag univoco per ogni elemento che verrà creato dal set di righe.
  • La seconda colonna deve contenere il numero di tag dell'elemento padre. Il nome della colonna deve essere Parent. In questo modo, le colonne Tag e Parent forniscono informazioni di gerarchia.

I valori di queste colonne di metadati, con le informazioni contenute nei nomi di colonna, vengono utilizzati per produrre il codice XML desiderato. Si noti che nella query è necessario fornire i nomi delle colonne in modo specifico. Si noti inoltre che un valore 0 o NULL nella colonna Parent indica che l'elemento corrispondente non ha un elemento padre. L'elemento viene aggiunto al codice XML come elemento di livello principale.

Per comprendere il modo in cui la tabella universale generata da una query viene elaborata per generare il codice XML risultante, si supponga di aver creato una query che produce la tabella universale seguente:

Tabella universale di esempio

Dalla tabella universale si noti quanto segue:

  • Le prime due colonne sono Tag e Parent e sono colonne di metadati. Questi valori determinano la gerarchia.
  • I nomi delle colonne sono formulati in un modo specifico, descritto di seguito in questo argomento.
  • Durante la generazione del codice XML da questa tabella universale, i dati della tabella vengono partizionati verticalmente in gruppi di colonne. Il raggruppamento viene determinato in base al valore di Tag e ai nomi delle colonne. Nella generazione del codice XML, la logica di elaborazione seleziona un gruppo di colonne per riga e costruisce un elemento. In questo esempio avviene quanto segue:
    • Per il valore 1 della colonna Tag nella prima riga, le colonne i cui nomi includono lo stesso numero di tag, Customer!1!cid e Customer!1!name, formano un gruppo. Queste colonne vengono utilizzate per l'elaborazione della riga e si può notare che la forma dell'elemento generato è <Customer id=... name=...>. Il formato del nome di colonna è descritto di seguito in questo argomento.
    • Per le righe con valore 2 nella colonna Tag, le colonne Order!2!id e Order!2!date formano un gruppo che viene quindi utilizzato per la costruzione di elementi, <Order id=... date=... />.
    • Per le righe con valore 3 nella colonna Tag, le colonne OrderDetail!3!id!id e OrderDetail!3!pid!idref formano un gruppo. Ognuna di queste righe genera un elemento <OrderDetail id=... pid=...> da queste colonne.
  • Si noti che nella generazione della gerarchia XML le righe vengono elaborate in ordine. La gerarchia XML viene determinata come descritto di seguito:
    • La prima riga specifica il valore 1 di Tag e il valore NULL di Parent. L'elemento corrispondente, <Customer>, viene pertanto aggiunto nel codice XML come elemento di livello principale.

      <Customer cid="C1" name="Janine">
      
    • La seconda riga identifica il valore 2 di Tag e il valore 1 di Parent. L'elemento <Order> viene pertanto aggiunto come elemento figlio dell'elemento <Customer>.

      <Customer cid="C1" name="Janine">
         <Order id="O1" date="1/20/1996">
      
    • Le due righe successive identificano il valore 3 di Tag e il valore 2 di Parent. I due elementi <OrderDetail> vengono pertanto aggiunti come elementi figlio dell'elemento <Order>.

      <Customer cid="C1" name="Janine">
         <Order id="O1" date="1/20/1996">
            <OrderDetail id="OD1" pid="P1"/>
            <OrderDetail id="OD2" pid="P2"/>
      
    • L'ultima riga identifica 2 come valore di Tag e 1 come valore di Parent. Un altro elemento figlio <Order> viene pertanto aggiunto all'elemento padre <Customer>.

      <Customer cid="C1" name="Janine">
         <Order id="O1" date="1/20/1996">
            <OrderDetail id="OD1" pid="P1"/>
            <OrderDetail id="OD2" pid="P2"/>
         </Order>
         <Order id="O2" date="3/29/1997">
      </Customer>
      

Per riassumere, per generare il codice XML desiderato in modalità EXPLICIT vengono utilizzati i valori presenti nelle colonne di metadati Tag e Parent, le informazioni specificate nei nomi delle colonne e l'ordinamento corretto delle righe.

Ordinamento delle righe della tabella universale

Nella generazione del codice XML, le righe della tabella universale vengono elaborate in ordine. Per recuperare le istanze figlio corrette associate al rispettivo elemento padre, è pertanto necessario che le righe del set vengano ordinate in modo tale che il nodo dell'elemento padre sia seguito immediatamente dagli elementi figlio.

Specifica dei nomi delle colonne in una tabella universale

Quando si scrivono query in modalità EXPLICIT è necessario specificare i nomi delle colonne nel set di righe risultante utilizzando il formato specificato di seguito. I nomi delle colonne forniscono informazioni di trasformazione, fra cui nomi di elementi e attributi e altre informazioni, specificate utilizzando direttive.

Il formato generale è il seguente:

ElementName!TagNumber!AttributeName!Directive

Di seguito è fornita la descrizione delle parti del formato.

  • ElementName
    Identificatore generico risultante dell'elemento. Ad esempio, se Customers viene specificato come ElementName, verrà generato l'elemento <Customers>.
  • TagNumber
    È un valore di tag univoco assegnato a un elemento. Questo valore, insieme alle due colonne di metadati Tag e Parent, determina la nidificazione degli elementi nel codice XML risultante.
  • AttributeName
    Fornisce il nome dell'attributo da costruire nell'argomento ElementName specificato. Ciò si verifica quando Directive non viene specificato.

    Se per Directive viene specificato xml, cdata oppure element, questo valore viene utilizzato per costruire un elemento figlio di ElementName, al quale viene aggiunto il valore della colonna.

    Se si specifica Directive, AttributeName può essere vuoto. Ad esempio, ElementName!TagNumber!!Directive. In questo caso, il valore della colonna è direttamente contenuto da ElementName.

  • Directive
    Directive è opzionale e può essere utilizzato per fornire informazioni aggiuntive per la generazione del codice XML. Directive svolge due funzioni.

    Il primo è la codifica dei valori come ID, IDREF e IDREFS. È possibile specificare le parole chiave ID, IDREFe IDREFS come direttive. Queste direttive sovrascrivono i tipi di attributo, consentendo di creare collegamenti tra più documenti.

    È inoltre possibile utilizzare Directive per definire il mapping tra i dati di tipo stringa e il codice XML. Le parole chiave hide, element, elementxsinil, xml, xmltext e cdata possono essere utilizzate come direttiva. La direttiva hide nasconde il nodo. È utile quando si recuperano i valori solo a scopo di ordinamento, ma non si desidera che vengano inseriti nel codice XML risultante.

    La direttiva element genera un elemento contenuto anziché un attributo. I dati contenuti vengono codificati come entità. Ad esempio, il carattere < viene convertito in &lt;. Per i valori di colonna NULL non vengono generati elementi. Se si desidera che venga generato un elemento anche per i valori di colonna NULL è possibile specificare la direttiva elementxsinil. Verrà generato un elemento con attributo xsi:nil=TRUE.

    La direttiva xml equivale a una direttiva element, ma non viene eseguita alcuna codifica di entità. Si noti che è possibile combinare la direttiva element con ID, IDREF o IDREFS, mentre la direttiva xml può essere utilizzata solo con hide.

    La direttiva cdata contiene i dati inserendoli in una sezione CDATA. Il contenuto non viene codificato come entità. I dati originali devono essere di tipo testo, ad esempio varchar, nvarchar, text o ntext. Questa direttiva può essere utilizzata solo con hide. Se si utilizza questa direttiva, non è necessario specificare AttributeName.

    Nella maggior parte dei casi è consentito combinare le direttive tra questi due gruppi, ma non è possibile combinarle tra loro.

    Se Directive e AttributeName non vengono specificati, ad esempio, Customer!1, è implicita una direttiva element, ad esempio Customer!1!!element e i dati di colonna sono contenuti in ElementName.

    Se si specifica la direttiva xmltext il contenuto della colonna viene inserito in un unico tag che viene integrato con il resto del documento. Questa direttiva risulta utile nel recupero dei dati XML di overflow (non utilizzati) archiviati in una colonna tramite OPENXML. Per ulteriori informazioni, vedere Esecuzione di query su codice XML tramite OPENXML.

    Se si specifica AttributeName il nome del tag viene sostituito dal nome specificato. In caso contrario, l'attributo viene aggiunto all'elenco corrente di attributi degli elementi che lo racchiudono inserendo il contenuto all'inizio dell'oggetto di contenimento senza codifica di entità. La colonna con questa direttiva deve essere di tipo testo, ad esempio varchar, nvarchar, char, nchar, text o ntext. Questa direttiva può essere utilizzata solo con hide. Risulta particolarmente utile per il recupero dei dati di overflow archiviati in una colonna. Se il contenuto non è in un formato XML corretto, il funzionamento non è prevedibile.

Esempi

Negli esempi seguenti viene illustrato l'utilizzo della modalità EXPLICIT.

A. Recupero di informazioni relative ai dipendenti

In questo esempio vengono recuperati ID e nome di ogni dipendente. Nel database AdventureWorks è possibile ottenere il valore employeeID dalla tabella Employee. I nomi dei dipendenti possono essere ottenuti dalla tabella Contact. La colonna ContactID può essere utilizzata per unire in join le tabelle.

Si supponga di voler utilizzare la trasformazione FOR XML EXPLICIT per generare codice XML come illustrato di seguito:

<Employee EmpID="1" >
  <Name FName="Guy" LName="Gilbert" />
</Employee>
...

Poiché la gerarchia contiene due livelli, è necessario scrivere due query SELECT e applicare UNION ALL. Questa è la prima query che recupera i valori per l'elemento <Employee> e i relativi attributi. La query assegna 1 come valore di Tag per l'elemento <Employee> e NULL come Parent, poiché si tratta dell'elemento di livello principale.

SELECT 1    as Tag,
       NULL as Parent,
       EmployeeID as [Employee!1!EmpID],
       NULL       as [Name!2!FName],
       NULL       as [Name!2!LName]
FROM   HumanResources.Employee E, Person.Contact C
WHERE  E.ContactID = C.ContactID

Di seguito è riportata la seconda query, che recupera i valori per l'elemento <Name>. Assegna 2 come valore di Tag per l'elemento <Name> e 1 come valore di tag Parent, identificando <Employee> come elemento padre.

SELECT 2 as Tag,
       1 as Parent,
       EmployeeID,
       FirstName, 
       LastName 
FROM   HumanResources.Employee E, Person.Contact C
WHERE  E.ContactID = C.ContactID

È necessario combinare le query con UNION ALL, applicare FOR XML EXPLICIT e specificare la clausola necessaria ORDER BY. Il set di righe va ordinato prima per EmployeeID e quindi per nome, in modo che i valori NULL nel nome vengano visualizzati per primi. Eseguendo la query successiva senza la clausola FOR XML viene generata la tabella universale.

La query finale sarà pertanto:

SELECT 1    as Tag,
       NULL as Parent,
       EmployeeID as [Employee!1!EmpID],
       NULL       as [Name!2!FName],
       NULL       as [Name!2!LName]
FROM   HumanResources.Employee E, Person.Contact C
WHERE  E.ContactID = C.ContactID
UNION ALL
SELECT 2 as Tag,
       1 as Parent,
       EmployeeID,
       FirstName, 
       LastName 
FROM   HumanResources.Employee E, Person.Contact C
WHERE  E.ContactID = C.ContactID
ORDER BY [Employee!1!EmpID],[Name!2!FName]
FOR XML EXPLICIT

Risultato parziale:

<Employee EmpID="1">
  <Name FName="Guy" LName="Gilbert" />
</Employee>
<Employee EmpID="2">
  <Name FName="Kevin" LName="Brown" />
</Employee>
...

La prima istruzione SELECT specifica i nomi per le colonne nel set di righe risultante. I nomi formano due gruppi di colonne. Il gruppo con valore di Tag pari a 1 nel nome della colonna identifica Employee come elemento e EmpID come attributo. L'altro gruppo di colonne contiene il valore di Tag 2 nella colonna e identifica <Name> come elemento e FName e LName come attributi.

La tabella seguente mostra il set di righe parziale generato dalla query:

Tag Parent  Employee!1!EmpID Name!2!FName Name!2!LName
----------- ----------- ---------------- -------------------
1    NULL     1                NULL          NULL
2     1       1                Guy           Gilbert
1    NULL     2                NULL          NULL
2     1       2                Kevin         Brown
1    NULL     3                NULL          NULL
2     1       3                Roberto       Tamburello 
...

Di seguito viene descritto il processo di elaborazione delle righe della tabella universale per la creazione della struttura XML risultante:

La prima riga identifica il valore 1 di Tag. Viene pertanto identificato il gruppo di colonne con valore di Tag pari a 1, Employee!1!EmpID. Questa colonna identifica Employee come nome dell'elemento. Viene quindi creato un elemento <Employee> con attributi EmpID. A questi attributi vengono assegnati i valori di colonna corrispondenti.

La seconda riga contiene il valore 2 di Tag. Viene pertanto identificato il gruppo di colonne con valore di Tag pari a 2 nel nome della colonna, Name!2!FName, Name!2!LName. Questi nomi di colonna identificano Name come nome dell'elemento. Viene creato un elemento <Name> con attributi FName e LName. A questi attributi vengono quindi assegnati i valori di colonna corrispondenti. Questa riga identifica 1 come valore di Parent. Questo elemento figlio viene aggiunto all'elemento <Employee> precedente.

Il processo viene ripetuto per tutte le righe del set di righe. Si noti l'importanza dell'ordinamento delle righe nella tabella universale, in modo che l'istruzione FOR XML EXPLICIT possa elaborare il set di righe nell'ordine corretto e generare il codice XML desiderato.

B. Specifica della direttiva element

Questo esempio è simile all'esempio A, ma genera codice XML incentrato sugli attributi, come illustrato di seguito:

<Employee EmpID=...>
  <Name>
    <FName>...</FName>
    <LName>...</LName>
  </Name>
</Employee>

La query è la stessa, ma si aggiunge la direttiva ELEMENT nei nomi delle colonne. <FName> e <LName> vengono pertanto aggiunti come elementi figlio dell'elemento <Name> invece che come attributi. Poiché la colonna Employee!1!EmpID non specifica la direttiva ELEMENT, EmpID viene aggiunto come attributo dell'elemento <Employee>.

SELECT 1 as Tag,
       NULL as Parent,
       EmployeeID as [Employee!1!EmpID],
       NULL       as [Name!2!FName!ELEMENT],
       NULL       as [Name!2!LName!ELEMENT]
FROM   HumanResources.Employee E, Person.Contact C
WHERE  E.ContactID = C.ContactID
UNION ALL
SELECT 2 as Tag,
       1 as Parent,
       EmployeeID,
       FirstName, 
       LastName 
FROM   HumanResources.Employee E, Person.Contact C
WHERE  E.ContactID = C.ContactID
ORDER BY [Employee!1!EmpID],[Name!2!FName!ELEMENT]
FOR XML EXPLICIT

Di seguito è riportato il risultato parziale.

<Employee EmpID="1">
  <Name>
    <FName>Guy</FName>
    <LName>Gilbert</LName>
  </Name>
</Employee>
<Employee EmpID="2">
  <Name>
    <FName>Kevin</FName>
    <LName>Brown</LName>
  </Name>
</Employee>
...

C. Specifica della direttiva elementxsinil

Quando si specifica la direttiva ELEMENT per il recupero di codice XML incentrato sugli elementi, se la colonna contiene un valore NULL l'elemento corrispondente non viene generato dalla modalità EXPLICIT. È possibile specificare facoltativamente la direttiva ELEMENTXSINIL per richiedere la generazione dell'elemento per i valori NULL. In questo caso l'attributo xsi:nil dell'elemento viene impostato sul valore TRUE.

La query seguente genera codice XML che include l'indirizzo di un dipendente. Per le colonne AddressLine2 e City, i nomi di colonna specificano la direttiva ELEMENTXSINIL. La direttiva produce la generazione dell'elemento per i valori NULL nelle colonne AddressLine2 e City nel set di righe.

SELECT 1    as Tag,
       NULL as Parent,
       EmployeeID  as [Employee!1!EmpID],
       E.AddressID as [Employee!1!AddressID],
       NULL        as [Address!2!AddressID],
       NULL        as [Address!2!AddressLine1!ELEMENT],
       NULL        as [Address!2!AddressLine2!ELEMENTXSINIL],
       NULL        as [Address!2!City!ELEMENTXSINIL]
FROM   HumanResources.EmployeeAddress E, Person.Address A
WHERE  E.ContactID = A.ContactID
UNION ALL
SELECT 2 as Tag,
       1 as Parent,
       EmployeeID,
       E.AddressID,
       A.AddressID,
       AddressLine1, 
       AddressLine2,
       City 
FROM   HumanResources.EmployeeAddress E, Person.Address A
WHERE  E.AddressID = A.AddressID
ORDER BY [Employee!1!EmpID],[Address!2!AddressID]
FOR XML EXPLICIT

Risultato parziale:

<Employee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        EmpID="1" AddressID="61">
  <Address AddressID="61">
    <AddressLine1>7726 Driftwood Drive</AddressLine1>
    <AddressLine2 xsi:nil="true" />
    <City>Monroe</City>
  </Address>
</Employee>
...

D. Creazione di elementi di pari livello utilizzando la modalità EXPLICIT

Si supponga di voler generare codice XML che fornisca informazioni sugli ordini di vendita. Si noti che <SalesPerson> e <OrderDetail> sono elementi di pari livello. Ogni ordine include un elemento <OrderHeader>, un elemento <SalesPerson> e uno o più elementi <OrderDetail>.

<OrderHeader SalesOrderID=... OrderDate=... CustomerID=... >
  <SalesPerson SalesPersonID=... />
  <OrderDetail SalesOrderID=... LineTotal=... ProductID=... OrderQty=... />
  <OrderDetail SalesOrderID=... LineTotal=... ProductID=... OrderQty=.../>
      ...
</OrderHeader>
<OrderHeader ...</OrderHeader>

La query in modalità EXPLICIT genera questo codice XML. Si noti che la query specifica valori di Tag pari a 1 per l'elemento <OrderHeader>, pari a 2 per l'elemento <SalesPerson> e pari a 3 per l'elemento <OrderDetail>. Poiché <SalesPerson> e <OrderDetail> sono elementi di pari livello, la query specifica lo stesso valore di tag pari a 1 di Parent per l'identificazione dell'elemento <OrderHeader>.

SELECT  1 as Tag,
        0 as Parent,
        SalesOrderID  as [OrderHeader!1!SalesOrderID],
        OrderDate     as [OrderHeader!1!OrderDate],
        CustomerID    as [OrderHeader!1!CustomerID],
        NULL          as [SalesPerson!2!SalesPersonID],
        NULL          as [OrderDetail!3!SalesOrderID],
        NULL          as [OrderDetail!3!LineTotal],
        NULL          as [OrderDetail!3!ProductID],
        NULL          as [OrderDetail!3!OrderQty]
FROM   Sales.SalesOrderHeader
WHERE     SalesOrderID=43659 or SalesOrderID=43661
UNION ALL 
SELECT 2 as Tag,
       1 as Parent,
        SalesOrderID,
        NULL,
        NULL,
        SalesPersonID,  
        NULL,         
        NULL,         
        NULL,
        NULL         
FROM   Sales.SalesOrderHeader
WHERE     SalesOrderID=43659 or SalesOrderID=43661
UNION ALL
SELECT 3 as Tag,
       1 as Parent,
        SOD.SalesOrderID,
        NULL,
        NULL,
        SalesPersonID,
        SOH.SalesOrderID,
        LineTotal,
        ProductID,
        OrderQty   
FROM    Sales.SalesOrderHeader SOH,Sales.SalesOrderDetail SOD
WHERE   SOH.SalesOrderID = SOD.SalesOrderID
AND     (SOH.SalesOrderID=43659 or SOH.SalesOrderID=43661)
ORDER BY [OrderHeader!1!SalesOrderID], [SalesPerson!2!SalesPersonID],
         [OrderDetail!3!SalesOrderID],[OrderDetail!3!LineTotal]
FOR XML EXPLICIT

Risultato parziale:

<OrderHeader SalesOrderID="43659" OrderDate="2001-07-01T00:00:00" CustomerID="676">
  <SalesPerson SalesPersonID="279" />
  <OrderDetail SalesOrderID="43659" LineTotal="10.373000" ProductID="712" OrderQty="2" />
  <OrderDetail SalesOrderID="43659" LineTotal="28.840400" ProductID="716" OrderQty="1" />
  <OrderDetail SalesOrderID="43659" LineTotal="34.200000" ProductID="709" OrderQty="6" />
   ...
</OrderHeader>
<OrderHeader SalesOrderID="43661" OrderDate="2001-07-01T00:00:00" CustomerID="442">
  <SalesPerson SalesPersonID="282" />
  <OrderDetail SalesOrderID="43661" LineTotal="20.746000" ProductID="712" OrderQty="4" />
  <OrderDetail SalesOrderID="43661" LineTotal="40.373000" ProductID="711" OrderQty="2" />
   ...
</OrderHeader>

E. Specifica delle direttive ID, IDREF

Questo esempio è uguale all'esempio C, con la differenza che la query specifica le direttive ID, IDREF. Queste direttive sovrascrivono i tipi dell'attributo SalesPersonID negli elementi <OrderHeader> e <OrderDetail>, creando collegamenti tra più documenti. Per visualizzare i tipi sovrascritti è necessario lo schema. La query specifica pertanto l'opzione XMLDATA nella clausola FOR XML per ottenere il recupero dello schema.

SELECT  1 as Tag,
        0 as Parent,
        SalesOrderID  as [OrderHeader!1!SalesOrderID!id],
        OrderDate     as [OrderHeader!1!OrderDate],
        CustomerID    as [OrderHeader!1!CustomerID],
        NULL          as [SalesPerson!2!SalesPersonID],
        NULL          as [OrderDetail!3!SalesOrderID!idref],
        NULL          as [OrderDetail!3!LineTotal],
        NULL          as [OrderDetail!3!ProductID],
        NULL          as [OrderDetail!3!OrderQty]
FROM   Sales.SalesOrderHeader
WHERE  SalesOrderID=43659 or SalesOrderID=43661
UNION ALL 
SELECT 2 as Tag,
       1 as Parent,
        SalesOrderID, 
        NULL,
        NULL,
        SalesPersonID,  
        NULL,         
        NULL,         
        NULL,
        NULL         
FROM   Sales.SalesOrderHeader
WHERE  SalesOrderID=43659 or SalesOrderID=43661
UNION ALL
SELECT 3 as Tag,
       1 as Parent,
        SOD.SalesOrderID,
        NULL,
        NULL,
        SalesPersonID,
        SOH.SalesOrderID,
        LineTotal,
        ProductID,
        OrderQty   
FROM    Sales.SalesOrderHeader SOH,Sales.SalesOrderDetail SOD
WHERE   SOH.SalesOrderID = SOD.SalesOrderID
AND     (SOH.SalesOrderID=43659 or SOH.SalesOrderID=43661)
ORDER BY [OrderHeader!1!SalesOrderID!id], [SalesPerson!2!SalesPersonID],
         [OrderDetail!3!SalesOrderID!idref],[OrderDetail!3!LineTotal]
FOR XML EXPLICIT, XMLDATA

Di seguito è riportato il risultato parziale. Nello schema, si noti che le direttive ID, IDREF hanno sovrascritto i tipi di dati dell'attributo SalesOrderID negli elementi <OrderHeader> e <OrderDetail>. Rimuovendo le direttive, lo schema restituisce i tipi originali degli attributi.

<Schema name="Schema1" xmlns="urn:schemas-microsoft-com:xml-data" xmlns:dt="urn:schemas-microsoft-com:datatypes">
  <ElementType name="OrderHeader" content="mixed" model="open">
    <AttributeType name="SalesOrderID" dt:type="id" />
    <AttributeType name="OrderDate" dt:type="dateTime" />
    <AttributeType name="CustomerID" dt:type="i4" />
    <attribute type="SalesOrderID" />
    <attribute type="OrderDate" />
    <attribute type="CustomerID" />
  </ElementType>
  <ElementType name="SalesPerson" content="mixed" model="open">
    <AttributeType name="SalesPersonID" dt:type="i4" />
    <attribute type="SalesPersonID" />
  </ElementType>
  <ElementType name="OrderDetail" content="mixed" model="open">
    <AttributeType name="SalesOrderID" dt:type="idref" />
    <AttributeType name="LineTotal" dt:type="number" />
    <AttributeType name="ProductID" dt:type="i4" />
    <AttributeType name="OrderQty" dt:type="i2" />
    <attribute type="SalesOrderID" />
    <attribute type="LineTotal" />
    <attribute type="ProductID" />
    <attribute type="OrderQty" />
  </ElementType>
</Schema>
<OrderHeader xmlns="x-schema:#Schema1" SalesOrderID="43659" OrderDate="2001-07-01T00:00:00" CustomerID="676">
  <SalesPerson SalesPersonID="279" />
  <OrderDetail SalesOrderID="43659" LineTotal="10.373000" ProductID="712" OrderQty="2" />
  ...
</OrderHeader>
...

F. Specifica delle direttive ID, IDREFS

Un attributo dell'elemento può essere specificato come attributo di tipo ID e gli attributi IDREFS possono quindi essere utilizzati per fare riferimento a tale attributo. In questo modo è possibile creare collegamenti tra più documenti, in modo analogo alla relazione tra chiave primaria e chiave esterna nei database relazionali.

Nell'esempio seguente viene illustrato l'utilizzo delle direttive ID e IDREFS per la creazione di attributi dei tipi ID e IDREFS. Poiché gli ID non possono essere valori Integer, nell'esempio i valori di ID vengono convertiti, ovvero ne viene eseguito il cast a un tipo compatibile. Vengono utilizzati prefissi per i valori degli ID.

Si supponga di voler generare codice XML come illustrato di seguito:

<Customer CustomerID="C1" SalesOrderIDList=" O11 O22 O33..." >
    <SalesOrder SalesOrderID="O11" OrderDate="..." />
    <SalesOrder SalesOrderID="O22" OrderDate="..." />
    <SalesOrder SalesOrderID="O33" OrderDate="..." />
    ...
</Customer>

L'attributo SalesOrderIDList dell'elemento < Customer > è un attributo multivalore che fa riferimento all'attributo SalesOrderID dell'elemento < SalesOrder >. Per stabilire il collegamento, è necessario dichiarare l'attributo SalesOrderID con il tipo di dati ID e l'attributo SalesOrderIDList dell'elemento < Customer> con il tipo di dati IDREFS. Poiché un cliente può inviare più ordini, viene utilizzato il tipo IDREFS.

Anche gli attributi IDREFS hanno più di un valore. È pertanto necessario utilizzare una clausola SELECT separata che riutilizzerà le stesse informazioni di Tag, Parent e colonna chiave. È poi necessario utilizzare ORDER BY per garantire che le sequenze di righe che compongono i valori IDREFS vengano visualizzate raggruppate sotto il rispettivo elemento padre.

Di seguito è riportata la query che genera il codice XML desiderato. La query utilizza le direttive ID, IDREFS per sovrascrivere i tipi nei nomi delle colonne (SalesOrder!2!SalesOrderID!ID, Customer!1!SalesOrderIDList!IDREFS).

SELECT  1 as Tag,
        0 as Parent,
        C.CustomerID       [Customer!1!CustomerID],
        NULL               [Customer!1!SalesOrderIDList!IDREFS],
        NULL               [SalesOrder!2!SalesOrderID!ID],
        NULL               [SalesOrder!2!OrderDate]
FROM   Sales.Customer C 
UNION ALL 
SELECT  1 as Tag,
        0 as Parent,
        C.CustomerID,
        'O-'+CAST(SalesOrderID as varchar(10)), 
        NULL,
        NULL
FROM   Sales.Customer C, Sales.SalesOrderHeader SOH
WHERE  C.CustomerID = SOH.CustomerID
UNION ALL
SELECT 2 as Tag,
       1 as Parent,
        C.CustomerID,
        NULL,
        'O-'+CAST(SalesOrderID as varchar(10)),
        OrderDate
FROM   Sales.Customer C, Sales.SalesOrderHeader SOH
WHERE  C.CustomerID = SOH.CustomerID
ORDER BY [Customer!1!CustomerID] ,
         [SalesOrder!2!SalesOrderID!ID],
         [Customer!1!SalesOrderIDList!IDREFS]
FOR XML EXPLICIT

G. Utilizzo della direttiva hide per nascondere elementi e attributi nel codice XML risultante

Nell'esempio seguente viene illustrato l'utilizzo della direttiva hide. Questa direttiva risulta utile quando si desidera la restituzione di un attributo in base al quale ordinare le righe nella tabella universale restituita dalla query, ma non si desidera che tale attributo venga visualizzato nel documento XML finale.

La query genera il codice XML seguente:

<ProductModel ProdModelID="19" Name="Mountain-100">
  <Summary>
    <SummaryDescription>
           <Summary> element from XML stored in CatalogDescription column
    </SummaryDescription>
  </Summary>
</ProductModel>

Questa query genera il codice XML desiderato. La query identifica due gruppi di colonne con valori di Tag 1 e 2 nei nomi delle colonne.

Il metodo query() (tipo di dati XML) del tipo di dati xml viene utilizzato per eseguire la query sulla colonna CatalogDescription di tipo xml e recuperare la descrizione di riepilogo. La query utilizza inoltre il metodo value() (tipo di dati XML) del tipo di dati xml per il recupero del valore ProductModelID dalla colonna CatalogDescription. Questo valore non è necessario nel codice XML risultante, ma lo è per ordinare il set di righe risultante. Il nome della colonna [Summary!2!ProductModelID!hide] include pertanto la direttiva hide. Se questa colonna non viene inclusa nell'istruzione SELECT sarà necessario ordinare il set di righe per [ProductModel!1!ProdModelID] e [Summary!2!SummaryDescription] che sono di tipo xml e non sarà possibile utilizzare la colonna di tipo xml in ORDER BY. Viene pertanto aggiunta la colonna [Summary!2!ProductModelID!hide], che viene poi specificata nella clausola ORDER BY.

SELECT  1 as Tag,
        0 as Parent,
        ProductModelID     as [ProductModel!1!ProdModelID],
        Name               as [ProductModel!1!Name],
        NULL               as [Summary!2!ProductModelID!hide],
        NULL               as [Summary!2!SummaryDescription]
FROM    Production.ProductModel
WHERE   CatalogDescription is not null
UNION ALL
SELECT  2 as Tag,
        1 as Parent,
        ProductModelID,
        Name,
        CatalogDescription.value('
         declare namespace PD="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription";
       (/PD:ProductDescription/@ProductModelID)[1]', 'int'),
        CatalogDescription.query('
         declare namespace pd="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription";
         /pd:ProductDescription/pd:Summary')
FROM    Production.ProductModel
WHERE   CatalogDescription is not null
ORDER BY [ProductModel!1!ProdModelID],[Summary!2!ProductModelID!hide]
FOR XML EXPLICIT
go

Risultato:

<ProductModel ProdModelID="19" Name="Mountain-100">
  <Summary>
    <SummaryDescription>
      <pd:Summary xmlns:pd="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription" >
        <p1:p xmlns:p1="http://www.w3.org/1999/xhtml">Our top-of-the-line competition mountain bike. Performance-enhancing options include the innovative HL Frame, super-smooth front suspension, and traction for all terrain. </p1:p>
      </pd:Summary>
    </SummaryDescription>
  </Summary>
</ProductModel>

H. Specifica della direttiva element e della codifica di entità

In questo esempio viene illustrata la differenza fra le direttive element e xml. La direttiva element sostituisce i dati con entità, la direttiva xml non esegue questa operazione. Nella query, all'elemento <Summary> viene assegnato codice XML, <Summary>This is summary description</Summary>.

Si consideri la seguente query:

SELECT  1 as Tag,
        0 as Parent,
        ProductModelID  as [ProductModel!1!ProdModelID],
        Name            as [ProductModel!1!Name],
        NULL            as [Summary!2!SummaryDescription!ELEMENT]
FROM    Production.ProductModel
WHERE   ProductModelID=19
UNION ALL
SELECT  2 as Tag,
        1 as Parent,
        ProductModelID,
        NULL,
       '<Summary>This is summary description</Summary>'
FROM   Production.ProductModel
WHERE  ProductModelID=19
FOR XML EXPLICIT

Di seguito è riportato il risultato. Nel risultato la descrizione di riepilogo viene sostituita con entità.

<ProductModel ProdModelID="19" Name="Mountain-100">
  <Summary>
    <SummaryDescription>&lt;Summary&gt;This is summary description&lt;/Summary&gt;</SummaryDescription>
  </Summary>
</ProductModel>

Se nel nome della colonna Summary!2!SummaryDescription!xml si specifica la direttiva xml invece della direttiva element, si otterrà la descrizione di riepilogo senza sostituzione con entità.

<ProductModel ProdModelID="19" Name="Mountain-100">
  <Summary>
    <SummaryDescription>
      <Summary>This is summary description</Summary>
    </SummaryDescription>
  </Summary>
</ProductModel>

Invece di assegnare un valore XML statico, la query seguente utilizza il metodo query() del tipo xml per recuperare la descrizione di riepilogo del modello di prodotto dalla colonna CatalogDescription di tipo xml. Poiché è noto che il risultato sarà di tipo xml, non viene applicata la sostituzione con entità.

SELECT  1 as Tag,
        0 as Parent,
        ProductModelID  as [ProductModel!1!ProdModelID],
        Name            as [ProductModel!1!Name],
        NULL            as [Summary!2!SummaryDescription]
FROM    Production.ProductModel
WHERE   CatalogDescription is not null
UNION ALL
SELECT  2 as Tag,
        1 as Parent,
        ProductModelID,
        Name,
       (SELECT CatalogDescription.query('
            declare namespace pd="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription";
          /pd:ProductDescription/pd:Summary'))
FROM     Production.ProductModel
WHERE    CatalogDescription is not null
ORDER BY [ProductModel!1!ProdModelID],Tag
FOR XML EXPLICIT

I. Specifica della direttiva cdata

Se si specifica la direttiva cdata, i dati contenuti non vengono codificati come entità, ma vengono inseriti nella sezione CDATA. Gli attributi cdata devono essere privi di nome.

La query seguente inserisce la descrizione di riepilogo del modello di prodotto in una sezione CDATA.

SELECT  1 as Tag,
        0 as Parent,
        ProductModelID  as [ProductModel!1!ProdModelID],
        Name            as [ProductModel!1!Name],
        '<Summary>This is summary description</Summary>'   
            as [ProductModel!1!!cdata] -- no attribute name so ELEMENT assumed
FROM    Production.ProductModel
WHERE   ProductModelID=19
FOR XML EXPLICIT

Risultato:

<ProductModel ProdModelID="19" Name="Mountain-100">
   <![CDATA[<Summary>This is summary description</Summary>]]>
</ProductModel>

I. Specifica della direttiva xmltext

Nell'esempio seguente viene illustrata la gestione dei dati nella colonna Overflow utilizzando la direttiva xmltext in un'istruzione SELECT in modalità EXPLICIT.

Si consideri la tabella Person. La tabella contiene una colonna Overflow che archivia la parte non utilizzata del documento XML.

CREATE TABLE Person(PersonID varchar(5), PersonName varchar(20), Overflow nvarchar(200))
INSERT INTO Person VALUES ('P1','Joe',N'<SomeTag attr1="data">content</SomeTag>')
INSERT INTO Person VALUES ('P2','Joe',N'<SomeTag attr2="data"/>')
INSERT INTO Person VALUES ('P3','Joe',N'<SomeTag attr3="data" PersonID="P">content</SomeTag>')

Questa query recupera colonne dalla tabella Person. Per la colonna Overflow non è specificato AttributeName, ma l'argomento directive è impostato su xmltext nell'ambito della specifica del nome della colonna della tabella universale.

SELECT 1 as Tag, NULL as parent,
       PersonID as [Parent!1!PersonID],
       PersonName as [Parent!1!PersonName],
       overflow as [Parent!1!!xmltext] -- No AttributeName; xmltext directive
FROM Person
FOR XML EXPLICIT

Nel documento XML risultante:

  • Poiché AttributeName non è specificato per la colonna Overflow ed è specificata la direttiva xmltext, gli attributi nell'elemento <overflow> vengono accodati all'elenco attributi dell'elemento <Parent> che li racchiude.
  • Poiché l'attributo PersonID nell'elemento <xmltext> è in conflitto con l'attributo PersonID rrecuperato allo stesso livello dell'elemento, l'attributo dell'elemento <xmltext> viene ignorato, anche se PersonID è NULL. In linea generale, un attributo prevarrà sull'attributo avente lo stesso nome nell'overflow.

Risultato:

<Parent PersonID="P1" PersonName="Joe" attr1="data">content</Parent>
<Parent PersonID="P2" PersonName="Joe" attr2="data"></Parent>
<Parent PersonID="P3" PersonName="Joe" attr3="data">content</Parent>

Se i dati di overflow includono sottoelementi e si specifica la stessa query, i sottoelementi nella colonna Overflow vengono aggiunti come sottoelementi dell'elemento <Parent> che li racchiude.

Ad esempio, si modifichino i dati della tabella Person in modo che la colonna Overflow includa sottoelementi.

TRUNCATE TABLE Person
INSERT INTO Person VALUES ('P1','Joe',N'<SomeTag attr1="data">content</SomeTag>')
INSERT INTO Person VALUES ('P2','Joe',N'<SomeTag attr2="data"/>')
INSERT INTO Person VALUES ('P3','Joe',N'<SomeTag attr3="data" PersonID="P"><name>PersonName</name></SomeTag>')

Se si esegue la stessa query, i sottoelementi dell'elemento <xmltext> vengono aggiunti come sottoelementi dell'elemento <Parent> che li racchiude:

SELECT 1 as Tag, NULL as parent,
       PersonID as [Parent!1!PersonID],
       PersonName as [Parent!1!PersonName],
       overflow as [Parent!1!!xmltext] -- no AttributeName, xmltext directive
FROM Person
FOR XML EXPLICIT

Risultato:

<Parent PersonID="P1" PersonName="Joe" attr1="data">content</Parent>
<Parent PersonID="P2" PersonName="Joe" attr2="data"></Parent>
<Parent PersonID="P3" PersonName="Joe" attr3="data">
  <name>PersonName</name>
</Parent>

Se si specifica AttributeName con la direttiva xmltext, gli attributi dell'elemento <overflow> vengono aggiunti come attributi dei sottoelementi dell'elemento <Parent> che li racchiude. Il nome specificato per AttributeName diventa il nome del sottoelemento.

Nella query seguente l'argomento AttributeName, <overflow>, viene specificato assieme alla direttiva xmltext*:*

SELECT 1 as Tag, NULL as parent,
       PersonID as [Parent!1!PersonID],
       PersonName as [Parent!1!PersonName],
       overflow as [Parent!1!overflow!xmltext] -- overflow is AttributeName
                      -- xmltext is directive
FROM Person
FOR XML EXPLICIT

Risultato:

<Parent PersonID="P1" PersonName="Joe">
  <overflow attr1="data">content</overflow>
</Parent>
<Parent PersonID="P2" PersonName="Joe">
  <overflow attr2="data" />
</Parent>
<Parent PersonID="P3" PersonName="Joe">
  <overflow attr3="data" PersonID="P">
    <name>PersonName</name>
  </overflow>
</Parent>

Nella query seguente l'argomento directive viene specificato per l'attributo PersonName. PersonName verrà pertanto aggiunto come sottoelemento dell'elemento <Parent> che lo racchiude. Gli attributi dell'elemento <xmltext> vengono accodati all'elemento <Parent> che li racchiude. Il contenuto dell'elemento <overflow> e i sottoelementi vengono anteposti agli altri sottoelementi degli elementi <Parent> che li racchiudono.

SELECT 1      as Tag, NULL as parent,
       PersonID   as [Parent!1!PersonID],
       PersonName as [Parent!1!PersonName!element], -- element directive
       overflow   as [Parent!1!!xmltext]
FROM Person
FOR XML EXPLICIT

Risultato:

<Parent PersonID="P1" attr1="data">content<PersonName>Joe</PersonName>
</Parent>
<Parent PersonID="P2" attr2="data">
  <PersonName>Joe</PersonName>
</Parent>
<Parent PersonID="P3" attr3="data">
  <name>PersonName</name>
  <PersonName>Joe</PersonName>
</Parent>

Se i dati della colonna xmltext includono attributi per l'elemento principale, tali attributi non compaiono nello schema dati XML e il parser MSXML non convalida il frammento di documento XML risultante. Ad esempio:

SELECT 1 as Tag,
       0 as Parent,
       N'<overflow a="1"/>' as 'overflow!1!!xmltext'
FOR XML EXPLICIT, xmldata

Di seguito è riportato il risultato. Si noti che l'attributo overflow a non è incluso nello schema restituito:

<Schema name="Schema2" 
        xmlns="urn:schemas-microsoft-com:xml-data" 
        xmlns:dt="urn:schemas-microsoft-com:datatypes">
  <ElementType name="overflow" content="mixed" model="open">
  </ElementType>
</Schema>
<overflow xmlns="x-schema:#Schema2" a="1">
</overflow> 

Vedere anche

Riferimento

Utilizzo della modalità RAW
Utilizzo della modalità AUTO
Costruzione di codice XML tramite la clausola FOR XML

Concetti

Utilizzo della modalità PATH

Altre risorse

SELECT (Transact-SQL)

Guida in linea e informazioni

Assistenza su SQL Server 2005