Condividi tramite


Sistema di tipi (XQuery)

XQuery è un linguaggio fortemente tipizzato per i tipi di schema e tipizzato in modo debole per i dati non tipizzati. I tipi predefiniti di XQuery sono:

Questo argomento descrive inoltre quanto segue:

Tipi predefiniti di schema XML

I tipi predefiniti di schema XML hanno un prefisso predefinito xs e includono, ad esempio, xs:integer e xs:string. Tutti questi tipi predefiniti sono supportati ed è possibile utilizzarli per la creazione di un insieme di schemi XML.

Quando si esegue una query su codice XML tipizzato, il tipo statico e dinamico dei nodi è determinato dall'insieme di schemi XML associato alla colonna o alla variabile su cui viene eseguita la query. Per ulteriori informazioni sui tipi statici e dinamici, vedere Contesto delle espressioni e valutazione delle query (XQuery). La query seguente viene ad esempio eseguita sulla colonna di tipo xml (Instructions). Nell'espressione viene utilizzato l'elemento instance of per verificare che il valore tipizzato dell'attributo LotSize restituito sia di tipo xs:decimal.

SELECT Instructions.query('
   DECLARE namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
   data(/AWMI:root[1]/AWMI:Location[@LocationID=10][1]/@LotSize)[1] instance of xs:decimal
') AS Result
FROM Production.ProductModel
WHERE ProductModelID=7

Queste informazioni relative alla tipizzazione vengono fornite dall'insieme di schemi XML associato alla colonna. Per ulteriori informazioni, vedere Rappresentazione del tipo di dati XML nel database AdventureWorks.

Tipi definiti nello spazio dei nomi dei tipi di dati XPath

I tipi definiti nello spazio dei nomi http://www.w3.org/2004/07/xpath-datatypes (informazioni in lingua inglese) hanno un prefisso predefinito xdt. Per questi tipi sono valide le osservazioni seguenti:

  • Non è possibile utilizzarli per la creazione di un insieme di schemi XML. Questi tipi vengono utilizzati nel sistema di tipi XQuery per la tipizzazione statica. È possibile eseguire il cast ai tipi atomici, ad esempio xdt:untypedAtomic, nello spazio dei nomi xdt.
  • Quando si esegue una query su codice XML non tipizzato, il tipo statico e dinamico dei nodi elemento è xdt:untyped e il tipo dei valori di attributo è xdt:untypedAtomic. Il risultato di un metodo query() genera codice XML non tipizzato. Ciò significa che i nodi XML vengono restituiti rispettivamente come xdt:untyped e xdt:untypedAtomic.
  • I tipi xdt:dayTimeDuration e xdt:yearMonthDuration non sono supportati.

Nell'esempio seguente, la query viene eseguita su una variabile XML non tipizzata. L'espressione data(/a[1]) restituisce una sequenza di un singolo valore atomico. La funzione data() restituisce il valore tipizzato dell'elemento <a>. Il codice XML su cui viene eseguita la query è non tipizzato e pertanto il tipo del valore restituito è xdt:untypedAtomic. Di conseguenza, instance of restituisce true.

DECLARE @x xml
SET @x='<a>20</a>'
SELECT @x.query( 'data(/a[1]) instance of xdt:untypedAtomic' )

Anziché recuperare il valore tipizzato, l'espressione (/a[1]) dell'esempio seguente restituisce una sequenza di un singolo elemento, ovvero l'elemento <a>. Questo elemento viene utilizzato dall'espressione instance of per verificare che il valore restituito dall'espressione sia un nodo elemento di tipo xdt:untyped type.

DECLARE @x xml
SET @x='<a>20</a>'
-- Is this an element node whose name is "a" and type is xdt:untyped.
SELECT @x.query( '/a[1] instance of element(a, xdt:untyped?)')
-- Is this an element node of type xdt:untyped.
SELECT @x.query( '/a[1] instance of element(*, xdt:untyped?)')
-- Is this an element node?
SELECT @x.query( '/a[1] instance of element()')

[!NOTA] Quando si esegue una query su un'istanza XML tipizzata e l'espressione della query include l'asse padre, le informazioni relative al tipo statico dei nodi risultanti non sono più disponibili. Il tipo dinamico rimane tuttavia associato ai nodi.

Valore tipizzato e valore stringa

A ogni nodo è associato un valore tipizzato e un valore stringa. Per i dati XML tipizzati, il tipo del valore tipizzato è fornito dall'insieme di schemi XML associato alla colonna o alla variabile su cui viene eseguita la query. Per i dati XML non tipizzati, il tipo del valore tipizzato è xdt:untypedAtomic.

Per recuperare il valore di un nodo è possibile utilizzare la funzione data() o string():

Nell'insieme di schemi XML seguente, viene definito l'elemento <root> di tipo integer:

CREATE XML SCHEMA COLLECTION SC AS N'
<schema xmlns="http://www.w3.org/2001/XMLSchema">
      <element name="root" type="integer"/>
</schema>'
GO

Nell'esempio seguente, l'espressione recupera innanzitutto il valore tipizzato di /root[1] e quindi vi aggiunge 3.

DECLARE @x xml(SC)
SET @x='<root>5</root>'
SELECT @x.query('data(/root[1]) + 3')

Nell'esempio seguente, l'espressione ha esito negativo perché string(/root[1]) restituisce un valore di tipo string. Questo valore viene quindi passato a un operatore aritmetico che utilizza solo valori di tipo numeric come operandi.

-- Fails because the argument is string type (must be numeric primitive type).
DECLARE @x xml(SC)
SET @x='<root>5</root>'
SELECT @x.query('string(/root[1]) + 3')

Nell'esempio seguente viene calcolato il totale degli attributi LaborHours. La funzione data() recupera i valori tipizzati degli attributi LaborHours da tutti gli elementi <Location> relativi a un modello di prodotto. In base allo schema XML associato alla colonna Instruction, LaborHours è di tipo xs:decimal.

SELECT Instructions.query(' 
DECLARE namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions"; 
             sum(data(//AWMI:Location/@LaborHours)) 
') AS Result 
FROM Production.ProductModel 
WHERE ProductModelID=7

Il risultato restituito dalla query è 12.75.

[!NOTA] In questo esempio, la funzione data() viene utilizzata in modo esplicito a solo scopo illustrativo. Se non viene specificata, sum() applica in modo implicito la funzione data() per estrarre i valori tipizzati dei nodi.

Individuazione di una corrispondenza per il tipo di sequenza

Il valore di un'espressione XQuery è sempre rappresentato da una sequenza di zero o più elementi, che possono essere valori atomici o nodi. Il tipo di sequenza fa riferimento alla capacità di stabilire una corrispondenza tra il tipo di sequenza restituito da un'espressione di query e un tipo specifico. Ad esempio:

  • Se il valore dell'espressione è atomico, è possibile stabilire se è di tipo integer, decimal o string.
  • Se il valore dell'espressione è un nodo XML, è possibile stabilire se è un nodo di commento, un nodo istruzione di elaborazione o un nodo di testo.
  • È possibile stabilire se l'espressione restituisce un elemento XML o un nodo di attributo con un nome e un tipo specifico.

Per individuare una corrispondenza per il tipo di sequenza, è possibile utilizzare l'operatore booleano instance of. Per ulteriori informazioni sull'espressione instance of, vedere Espressioni SequenceType (XQuery).

Confronto del tipo del valore atomico restituito da un'espressione

Se un'espressione restituisce una sequenza di valori atomici, potrebbe essere necessario trovare il tipo del valore nella sequenza. Negli esempi seguenti viene illustrato l'utilizzo della sintassi del tipo di sequenza per valutare il tipo di valore atomico restituito da un'espressione.

Esempio A

È possibile utilizzare il tipo di sequenza empty() in un'espressione SequenceType per determinare se la sequenza restituita dall'espressione specificata è vuota.

Nell'esempio seguente, lo schema XML consente che l'elemento <root> supporti i valori Null:

CREATE XML SCHEMA COLLECTION SC AS N'
<schema xmlns="http://www.w3.org/2001/XMLSchema">
      <element name="root" nillable="true" type="byte"/>
</schema>'
GO

Se un'istanza XML tipizzata specifica un valore per l'elemento <root>, instance of empty() restituisce False.

DECLARE @var XML(SC1)
SET @var = '<root>1</root>'
-- The following returns False
SELECT @var.query('data(/root[1]) instance of  empty() ')
GO

Se l'elemento <root> supporta i valori Null nell'istanza, il relativo valore è una sequenza vuota e instance of empty() restituisce True.

DECLARE @var XML(SC)
SET @var = '<root xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />'
SELECT @var.query('data(/root[1]) instance of  empty() ')
GO

Esempio B

A volte è possibile valutare il tipo di sequenza restituito da un'espressione prima dell'elaborazione. Ad esempio, si consideri uno schema XML nel quale un nodo è definito come un tipo unione. Nell'esempio seguente, lo schema XML dell'insieme definisce l'attributo a come un tipo unione il cui valore può essere di tipo decimal o string.

-- Drop schema collection if it exists.
-- DROP XML SCHEMA COLLECTION SC.
-- GO
CREATE XML SCHEMA COLLECTION SC AS N'
<schema xmlns="http://www.w3.org/2001/XMLSchema">
  <element name="root">
    <complexType>
       <sequence/>
         <attribute name="a">
            <simpleType>
               <union memberTypes="decimal string"/>
            </simpleType>
         </attribute>
     </complexType>
  </element>
</schema>'
GO

Prima di elaborare un'istanza XML tipizzata, è possibile determinare il tipo del valore dell'attributo a. Nell'esempio seguente, il valore dell'attributo a è di tipo decimal e pertanto , instance of xs:decimal restituisce True.

DECLARE @var XML(SC)
SET @var = '<root a="2.5"/>'
SELECT @var.query('data((/root/@a)[1]) instance of xs:decimal')
GO

L'attributo a viene modificato in un tipo string e pertanto instance of xs:string restituirà True.

DECLARE @var XML(SC)
SET @var = '<root a="Hello"/>'
SELECT @var.query('data((/root/@a)[1]) instance of xs:string')
GO

Esempio C

Nell'esempio seguente viene illustrato l'effetto della cardinalità in un'espressione di sequenza. Lo schema XML seguente definisce un elemento <root> che è di tipo byte e supporta i valori Null.

CREATE XML SCHEMA COLLECTION SC AS N'
<schema xmlns="http://www.w3.org/2001/XMLSchema">
      <element name="root" nillable="true" type="byte"/>
</schema>'
GO

Nella query seguente, dato che l'espressione restituisce un singleton di tipo byte, instance of restituisce True.

DECLARE @var XML(SC)
SET @var = '<root>111</root>'
SELECT @var.query('data(/root[1]) instance of  xs:byte ') 
GO

Se si imposta l'elemento <root> come Null, il relativo valore è una sequenza vuota ovvero l'espressione /root[1] restituisce una sequenza vuota e pertanto instance of xs:byte restituisce False. Si noti che in questo caso la cardinalità predefinita è 1.

DECLARE @var XML(SC)
SET @var = '<root xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"></root>'
SELECT @var.query('data(/root[1]) instance of  xs:byte ') 
GO
-- result = false

Se si specifica la cardinalità aggiungendo l'indicatore di occorrenza (?), l'espressione della sequenza restituisce True.

DECLARE @var XML(SC)
SET @var = '<root xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"></root>'
SELECT @var.query('data(/root[1]) instance of  xs:byte? ') 
GO
-- result = true

Si noti che il test di un'espressione SequenceType include due fasi:

  1. Il test determina innanzitutto se il tipo di espressione corrisponde al tipo specificato.
  2. In caso affermativo, il test determina se il numero di elementi restituiti dall'espressione corrisponde all'indicatore di occorrenza specificato.

Se entrambe le condizioni sono vere, l'espressione instance of restituisce True.

Esempio D

Nell'esempio seguente viene eseguita una query su una colonna Instructions di tipo xml nel database AdventureWorks. Si tratta di una colonna XML tipizzata, perché è associata a uno schema. Per ulteriori informazioni, vedere Rappresentazione del tipo di dati XML nel database AdventureWorks. Lo schema XML definisce l'attributo LocationID di tipo integer. Nell'espressione della sequenza, instance of xs:integer? restituisce pertanto True.

SELECT Instructions.query(' 
declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions"; 
data(/AWMI:root[1]/AWMI:Location[1]/@LocationID) instance of xs:integer?') as Result 
FROM Production.ProductModel 
WHERE ProductModelID = 7

Confronto del tipo di nodo restituito da un'espressione

Se un'espressione restituisce una sequenza di nodi, è possibile che sia necessario individuare il tipo di nodo nella sequenza. Nell'esempio seguente viene illustrata la sintassi del tipo che è possibile utilizzare per valutare il tipo di nodo restituito da un'espressione. È possibile utilizzare i tipi di sequenza seguenti:

  • item() – Stabilisce una corrispondenza per ogni elemento della sequenza.
  • node() – Determina se la sequenza è un nodo.
  • processing-instruction() – Determina se l'espressione restituisce un'istruzione di elaborazione.
  • comment() – Determina se l'espressione restituisce un commento.
  • document-node() – Determina se l'espressione restituisce un nodo di documento.

Negli esempi seguenti sono illustrati questi tipi di sequenza.

Esempio A

In questo esempio vengono eseguite numerose query su una variabile XML non tipizzata. Le query illustrano l'utilizzo dei tipi di sequenza.

DECLARE @var XML
SET @var = '<?xml-stylesheet href="someValue" type="text/xsl" ?>
<root>text node
  <!-- comment 1 --> 
  <a>Data a</a>
  <!-- comment  2 -->
</root>'

Nella prima query, l'espressione restituisce il valore tipizzato dell'elemento <a>. Nella seconda query, l'espressione restituisce l'elemento <a>. In entrambi i casi si tratta di elementi e pertanto entrambe le query restituiscono True.

SELECT @var.query('data(/root[1]/a[1]) instance of item()')
SELECT @var.query('/root[1]/a[1] instance of item()')

Tutte le espressioni XQuery nelle tre query seguenti restituiscono il nodo figlio dell'elemento <root>. L'espressione SequenceType instance of node() restituisce pertanto True e le altre due espressioni, instance of text() e instance of document-node(), restituiscono False.

SELECT @var.query('(/root/*)[1] instance of node()')
SELECT @var.query('(/root/*)[1] instance of text()')
SELECT @var.query('(/root/*)[1] instance of document-node()') 

Nella query seguente, l'espressione instance of document-node() restituisce True perché il padre dell'elemento <root> è un nodo di documento.

SELECT @var.query('(/root/..)[1] instance of document-node()') -- true

Nella query seguente, l'espressione recupera il primo nodo dall'istanza XML. Poiché è un nodo istruzione di elaborazione, l'espressione instance of processing-instruction() restituisce True.

SELECT @var.query('(/node())[1] instance of processing-instruction()')

Limitazioni di implementazione

Sono valide le limitazioni seguenti:

  • Il tipo document-node() non è supportato con la sintassi del tipo di contenuto.
  • La sintassi processing-instruction(name) non è supportata.

Test dell'elemento

Un test dell'elemento consente di stabilire una corrispondenza tra il nodo elemento restituito da un'espressione e un nodo elemento con un nome e un tipo specifico. Sono disponibili i test dell'elemento seguenti:

element ()
element(ElementName)
element(ElementName, ElementType?) 
element(*, ElementType?)

Test dell'attributo

Il test dell'attributo consente di stabilire se l'attributo restituito da un'espressione è un nodo di attributo. Sono disponibili i test dell'attributo seguenti:

attribute()

attribute(AttributeName)

attribute(AttributeName, AttributeType)

Esempi di test

Negli esempi seguenti vengono illustrati scenari nei quali i test dell'elemento e dell'attributo possono risultare utili.

Esempio A

Lo schema XML seguente definisce il tipo complesso CustomerType nel quale gli elementi <firstName> e <lastName> sono facoltativi. Per un'istanza XML specificata, potrebbe essere necessario stabilire se esiste il nome di un cliente specifico.

CREATE XML SCHEMA COLLECTION SC AS N'
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="myNS" xmlns:ns="myNS">
  <complexType name="CustomerType">
     <sequence>
        <element name="firstName" type="string" minOccurs="0" 
                  nillable="true" />
        <element name="lastName" type="string" minOccurs="0"/>
     </sequence>
  </complexType>
  <element name="customer" type="ns:CustomerType"/>
</schema>
'
GO
DECLARE @var XML(SC)
SET @var = '<x:customer xmlns:x="myNS">
<firstName>SomeFirstName</firstName>
<lastName>SomeLastName</lastName>
</x:customer>'

La query seguente utilizza un'espressione instance of element (firstName) per determinare se il primo elemento figlio di <customer> è un elemento denominato <firstName>. In caso affermativo, restituisce True.

SELECT @var.query('declare namespace x="myNS"; 
     (/x:customer/*)[1] instance of element (firstName)')
GO

Se si rimuove l'elemento <firstName> dall'istanza, la query restituirà False.

È inoltre possibile utilizzare:

  • La sintassi del tipo di sequenza element(ElementName, ElementType?), come illustrato nella query seguente. Tale sintassi stabilisce una corrispondenza per un nodo elemento denominato firstName e di tipo xs:string che supporta o non supporta i valori Null.

    SELECT @var.query('declare namespace x="myNS"; 
    (/x:customer/*)[1] instance of element (firstName, xs:string?)')
    
  • La sintassi del tipo di sequenza element(*, type?), come illustrato nella query seguente. Tale sintassi stabilisce una corrispondenza per il nodo elemento se è di tipo xs:string, indipendentemente dal nome.

    SELECT @var.query('declare namespace x="myNS"; (/x:customer/*)[1] instance of element (*, xs:string?)')
    GO
    

Esempio B

Nell'esempio seguente viene illustrato come determinare se il nodo restituito da un'espressione è un nodo elemento con un nome specifico, utilizzando il test element().

Nell'esempio seguente, i due elementi <Customer> dell'istanza XML sui quali viene eseguita la query sono di due tipi diversi, CustomerType e SpecialCustomerType. Si supponga di voler conoscere il tipo dell'elemento <Customer> restituito dall'espressione. L'insieme di schemi XML seguente definisce i tipi CustomerType e SpecialCustomerType.

CREATE XML SCHEMA COLLECTION SC AS N'
<schema xmlns="http://www.w3.org/2001/XMLSchema"
          targetNamespace="myNS"  xmlns:ns="myNS">
  <complexType name="CustomerType">
    <sequence>
      <element name="firstName" type="string"/>
      <element name="lastName" type="string"/>
    </sequence>
  </complexType>
  <complexType name="SpecialCustomerType">
     <complexContent>
       <extension base="ns:CustomerType">
        <sequence>
            <element name="Age" type="int"/>
        </sequence>
       </extension>
     </complexContent>
    </complexType>
   <element name="customer" type="ns:CustomerType"/>
</schema>
'
GO

Questo insieme di schemi XML consente di creare una variabile xml tipizzata. L'istanza XML assegnata alla variabile include due elementi <customer> di tipo diverso. l primo elemento è di tipo CustomerType e il secondo elemento è di tipo SpecialCustomerType.

DECLARE @var XML(SC)
SET @var = '
<x:customer xmlns:x="myNS">
   <firstName>FirstName1</firstName>
   <lastName>LastName1</lastName>
</x:customer>
<x:customer xsi:type="x:SpecialCustomerType" xmlns:x="myNS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <firstName> FirstName2</firstName>
   <lastName> LastName2</lastName>
   <Age>21</Age>
</x:customer>'

Nella query seguente, l'espressione instance of element (*, x:SpecialCustomerType ?) restituisce False, perché restituisce il primo elemento Customer che non è di tipo SpecialCustomerType.

SELECT @var.query('declare namespace x="myNS"; 
    (/x:customer)[1] instance of element (*, x:SpecialCustomerType ?)')

Se si modifica l'espressione della query precedente e si recupera il secondo elemento <customer> (/x:customer)[2]), instance of restituirà True.

Esempio C

In questo esempio viene utilizzato il test dell'attributo. Lo schema XML seguente definisce il tipo complesso CustomerType con gli attributi CustomerID e Age. L'attributo Age è facoltativo. È possibile determinare se nell'elemento <customer> di un'istanza XML specifica è presente l'attributo Age.

CREATE XML SCHEMA COLLECTION SC AS N'
<schema xmlns="http://www.w3.org/2001/XMLSchema"
       targetNamespace="myNS" xmlns:ns="myNS">
<complexType name="CustomerType">
  <sequence>
     <element name="firstName" type="string" minOccurs="0" 
               nillable="true" />
     <element name="lastName" type="string" minOccurs="0"/>
  </sequence>
  <attribute name="CustomerID" type="integer" use="required" />
  <attribute name="Age" type="integer" use="optional" />
 </complexType>
 <element name="customer" type="ns:CustomerType"/>
</schema>
'
GO

La query seguente restituisce True perché nell'istanza XML su cui viene eseguita la query esiste un nodo di attributo al quale è assegnato il nome Age. In questa espressione viene utilizzato il test dell'attributo attribute(Age). Gli attributi non sono ordinati, pertanto la query utilizza l'espressione FLWOR per recuperare tutti gli attributi e quindi testa ognuno di essi tramite l'espressione instance of. Nell'esempio viene innanzitutto creato un insieme di schemi XML tramite il quale è possibile creare una variabile xml tipizzata.

DECLARE @var XML(SC)
SET @var = '<x:customer xmlns:x="myNS" CustomerID="1" Age="22" >
<firstName>SomeFName</firstName>
<lastName>SomeLName</lastName>
</x:customer>'
SELECT @var.query('declare namespace x="myNS"; 
FOR $i in /x:customer/@*
RETURN
    IF ($i instance of attribute (Age)) THEN
        "true"
        ELSE
        ()')   
GO

Se si rimuove dall'istanza l'attributo facoltativo Age, la query precedente restituirà False.

Nel test dell'attributo è possibile specificare il nome e il tipo dell'attributo (attribute(name,type)).

SELECT @var.query('declare namespace x="myNS"; 
FOR $i in /x:customer/@*
RETURN
    IF ($i instance of attribute (Age, xs:integer)) THEN
        "true"
        ELSE
        ()')

In alternativa, è possibile specificare la sintassi del tipo di sequenza attribute(*, type). Se il tipo di attributo corrisponde al tipo specificato, in questo modo viene stabilita una corrispondenza per il nodo di attributo, indipendentemente dal nome.

Limitazioni di implementazione

Sono valide le limitazioni seguenti:

  • Nel test dell'elemento, è necessario che il nome del tipo sia seguito dall'indicatore di occorrenza (?).
  • element(ElementName, TypeName) non è supportata.
  • element(*, TypeName) non è supportata.
  • schema-element() non è supportata.
  • schema-attribute(AttributeName) non è supportata.
  • L'esecuzione di query in modo esplicito per xsi:type o xsi:nil non è supportata.

Vedere anche

Concetti

Espressioni SequenceType (XQuery)
Nozioni fondamentali su XQuery

Altre risorse

Utilizzo di SQL Server Profiler

Guida in linea e informazioni

Assistenza su SQL Server 2005