Espressioni SequenceType (XQuery)

In XQuery un valore è sempre una sequenza. Il tipo del valore viene definito tipo di sequenza. Il tipo di sequenza può essere utilizzato in un'espressione XQuery instance of. La sintassi SequenceType descritta nella specifica XQuery viene utilizzata quando è necessario fare riferimento a un tipo in un'espressione XQuery.

Nell'espressione XQuery cast as è inoltre possibile utilizzare il tipo di nome atomico. In SQL Server le espressioni XQuery instance of e cast as sui tipi di sequenza sono supportate solo in parte.

Operatore instance of

L'operatore instance of può essere utilizzato per determinare il tipo dinamico, o tipo in fase di esecuzione, del valore dell'espressione specificata. Ad esempio:

          Expression instance of SequenceType[Occurrence indicator]

Si noti che l'operatore instance of , Occurrence indicator, specifica la cardinalità, ovvero il numero di elementi della sequenza risultante. Se non viene specificato, si presuppone una cardinalità 1. In SQL Server, è supportato solo l'indicatore di occorrenza punto interrogativo (?) . L'indicatore di occorrenza ? indica che Expression può restituire zero o un elemento. Se si specifica l'indicatore di occorrenza ?, instance of restituisce True quando il tipo di Expression corrisponde al SequenceType specificato, indipendentemente dal fatto che Expression restituisca un singleton o una sequenza vuota.

Se l'indicatore di occorrenza ? non viene specificato, sequence of restituisce True solo quando il tipo di Expression corrisponde al Type specificato e Expression restituisce un singleton.

Nota Gli indicatori di occorrenza segno più (+) e asterisco (*) non sono supportati in SQL Server.

Nell'esempio seguente viene illustrato l'utilizzo dell'operatore XQueryinstance of.

Esempio A

Nell'esempio seguente viene creata una variabile di tipo xml e viene specificata l'esecuzione di una query sulla variabile. L'espressione di query specifica un operatore instance of per determinare se il tipo dinamico del valore restituito dal primo operando corrisponde al tipo specificato nel secondo operando.

La query seguente restituisce True, poiché il valore 125 è un'istanza del tipo specificato, ovvero xs:integer:

declare @x xml
set @x=''
select @x.query('125 instance of xs:integer')
go

La query seguente restituisce True, poiché il valore restituito dall'espressione /a[1] nel primo operando è un elemento:

declare @x xml
set @x='<a>1</a>'
select @x.query('/a[1] instance of element()')
go

Allo stesso modo, instance of restituisce True nella query seguente poiché il tipo di valore dell'espressione nella prima espressione è un attributo:

declare @x xml
set @x='<a attr1="x">1</a>'
select @x.query('/a[1]/@attr1 instance of attribute()')
go

Nell'esempio seguente, l'espressione data(/a[1] restituisce un valore atomico tipizzato come xdt:untypedAtomic. L'operatore instance of pertanto restituisce True.

declare @x xml
set @x='<a>1</a>'
select @x.query('data(/a[1]) instance of xdt:untypedAtomic')
go

Nella query seguente, l'espressione data(/a[1]/@attrA restituisce un valore atomico non tipizzato. L'operatore instance of pertanto restituisce True.

declare @x xml
set @x='<a attrA="X">1</a>'
select @x.query('data(/a[1]/@attrA) instance of xdt:untypedAtomic')
go

Esempio B

In questo esempio viene eseguita una query su una colonna XML tipizzata del database di esempio AdventureWorks2008R2. La raccolta di XML Schema associata alla colonna sulla quale viene eseguita la query fornisce le informazioni di tipizzazione.

Nell'espressione, data() restituisce il valore tipizzato dell'attributo ProductModelID, il cui tipo, in base allo schema associato alla colonna, è xs:string. L'operatore instance of pertanto restituisce True.

SELECT CatalogDescription.query('
   declare namespace PD="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription";
   data(/PD:ProductDescription[1]/@ProductModelID) instance of xs:string
') as Result
FROM Production.ProductModel
WHERE ProductModelID = 19

Per ulteriori informazioni, vedere Dati XML tipizzati confrontati con dati XML non tipizzati. Per informazioni sulla raccolta di XML Schema associata alla colonna CatalogDescription, vedere Informazioni sulla colonna xml ProductModel.CatalogDescription.

Nelle query seguenti viene utilizzatal'espressionebooleana instance of per determinare se l'attributo LocationID sia di tipo xs:integer:

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

La query seguente viene specificata sulla colonna XML tipizzata CatalogDescription. Le informazioni di tipizzazione sono fornite dalla raccolta di XML Schema associata alla colonna. Per ulteriori informazioni sulla raccolta di XML Schema, vedere Informazioni sulla colonna xml ProductModel.CatalogDescription.

La query utilizza il test element(ElementName, ElementType?) nell'espressione instance of per verificare che /PD:ProductDescription[1] restituisca un nodo di elemento con un nome e un tipo specifici.

SELECT CatalogDescription.query('
     declare namespace PD="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription";
     /PD:ProductDescription[1] instance of element(PD:ProductDescription, PD:ProductDescription?)
    ') as Result
FROM  Production.ProductModel
where ProductModelID=19

La query restituisce True.

Esempio C

Quando si utilizzano i tipi unione, l'espressione instance of in SQL Server presenta una limitazione. In particolare, quando un elemento o un attributo è di un tipo unione, è possibile che instance of non riesca a determinare il tipo esatto. Di conseguenza, una query restituirà False, a meno che i tipi atomici utilizzati in SequenceType siano l'elemento padre di livello più alto del tipo effettivo dell'espressione nella gerarchia simpleType, ovvero che i tipi atomici specificati in SequenceType siano figli diretti di anySimpleType. Per informazioni sulla gerarchia tipi, vedere Regole del cast dei tipi in XQuery.

La prossima query esegue le operazioni seguenti:

  • Crea a una raccolta di XML Schema contenente la definizione di un tipo unione, ad esempio un tipo integer o stringa.

  • Dichiara una variabile xml tipizzata utilizzando la raccolta di XML Schema.

  • Assegna un'istanza XML di esempio alla variabile.

  • Esegue una query sulla variabile per illustrare il funzionamento di instance of quando è applicato a un tipo unione.

Di seguito è riportata la query:

CREATE XML SCHEMA COLLECTION MyTestSchema AS '
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://ns" xmlns:ns="http://ns">
<simpleType name="MyUnionType">
<union memberTypes="integer string"/>
</simpleType>
<element name="TestElement" type="ns:MyUnionType"/>
</schema>'
Go

La query seguente restituisce False, perché il SequenceType specificato nell'espressione instance of non è l'elemento padre di livello più alto del tipo effettivo dell'espressione specificata. Il valore dell'elemento <TestElement> è infatti un tipo integer. L'elemento padre di livello più alto è xs:decimal, ma non è specificato come secondo operando dell'operatore instance of.

SET QUOTED_IDENTIFIER ON
DECLARE @var XML(MyTestSchema)

SET @var = '<TestElement xmlns="http://ns">123</TestElement>'

SELECT @var.query('declare namespace ns="http://ns" 
   data(/ns:TestElement[1]) instance of xs:integer')
go

Poiché l'elemento padre di livello più alto di xs:integer è xs:decimal, se viene modificata specificando xs:decimal come SequenceType la query restituirà True.

SET QUOTED_IDENTIFIER ON
DECLARE @var XML(MyTestSchema)
SET @var = '<TestElement xmlns="http://ns">123</TestElement>'
SELECT @var.query('declare namespace ns="http://ns"   
   data(/ns:TestElement[1]) instance of xs:decimal')
go

Esempio D

Nell'esempio seguente viene creata una raccolta di XML Schema e la si utilizza per tipizzare una variabile xml. Viene quindi eseguita una query sulla variabile xml tipizzata per illustrare la funzionalità instance of.

La raccolta di XML Schema seguente definisce il tipo semplice myType e un elemento, <root>, di tipo myType:

drop xml schema collection SC
go
CREATE XML SCHEMA COLLECTION SC AS '
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="myNS" xmlns:ns="myNS"
xmlns:s="https://schemas.microsoft.com/sqlserver/2004/sqltypes">
      <import namespace="https://schemas.microsoft.com/sqlserver/2004/sqltypes"/>
      <simpleType name="myType">
           <restriction base="s:varchar">
                  <maxLength value="20"/>
            </restriction>
      </simpleType>
      <element name="root" type="ns:myType"/>
</schema>'
Go

Si crei ora una variabile xml tipizzata e si esegua una query su di essa:

DECLARE @var XML(SC)
SET @var = '<root xmlns="myNS">My data</root>'
SELECT @var.query('declare namespace sqltypes = "https://schemas.microsoft.com/sqlserver/2004/sqltypes";
declare namespace ns="myNS"; 
   data(/ns:root[1]) instance of ns:myType')
go

Poiché il tipo myType deriva per restrizione da un tipo varchar definito nello schema sqltypes, anche instance of restituirà True.

DECLARE @var XML(SC)
SET @var = '<root xmlns="myNS">My data</root>'
SELECT @var.query('declare namespace sqltypes = "https://schemas.microsoft.com/sqlserver/2004/sqltypes";
declare namespace ns="myNS"; 
data(/ns:root[1]) instance of sqltypes:varchar?')
go

Esempio E

Nell'esempio seguente, l'espressione recupera uno dei valori dell'attributo IDREFS e utilizza instance of per determinare se il valore sia di tipo IDREF. L'esempio esegue le operazioni seguenti:

  • Crea una raccolta di XML Schema nella quale l'elemento <Customer> ha un attributo OrderList di tipo IDREFS e l'elemento <Order> ha un attributo OrderID di tipo ID.

  • Crea una variabile xml tipizzata e assegna un'istanza XML di esempio alla variabile.

  • Specifica una query sulla variabile. L'espressione della query recupera il valore di ID del primo ordine dall'attributo OrderList di tipo IDREFS del primo elemento <Customer>. Il valore recuperato è di tipo IDREF. L'operatore instance of pertanto restituisce True.

create xml schema collection SC as
'<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:Customers="Customers" targetNamespace="Customers">
            <element name="Customers" type="Customers:CustomersType"/>
            <complexType name="CustomersType">
                        <sequence>
                            <element name="Customer" type="Customers:CustomerType" minOccurs="0" maxOccurs="unbounded" />
                        </sequence>
            </complexType>
             <complexType name="OrderType">
                <sequence minOccurs="0" maxOccurs="unbounded">
                            <choice>
                                <element name="OrderValue" type="integer" minOccurs="0" maxOccurs="unbounded"/>
                            </choice>
                </sequence>                                           
                <attribute name="OrderID" type="ID" />
            </complexType>

            <complexType name="CustomerType">
                <sequence minOccurs="0" maxOccurs="unbounded">
                            <choice>
                                <element name="spouse" type="string" minOccurs="0" maxOccurs="unbounded"/>
                                <element name="Order" type="Customers:OrderType" minOccurs="0" maxOccurs="unbounded"/>
                            </choice>
                </sequence>                                           
                <attribute name="CustomerID" type="string" />
                <attribute name="OrderList" type="IDREFS" />
            </complexType>
 </schema>'
go
declare @x xml(SC)
set @x='<CustOrders:Customers xmlns:CustOrders="Customers">
                <Customer CustomerID="C1" OrderList="OrderA OrderB"  >
                              <spouse>Jenny</spouse>
                                <Order OrderID="OrderA"><OrderValue>11</OrderValue></Order>
                                <Order OrderID="OrderB"><OrderValue>22</OrderValue></Order>

                </Customer>
                <Customer CustomerID="C2" OrderList="OrderC OrderD" >
                                <spouse>John</spouse>
                                <Order OrderID="OrderC"><OrderValue>33</OrderValue></Order>
                                <Order OrderID="OrderD"><OrderValue>44</OrderValue></Order>

                        </Customer>
                <Customer CustomerID="C3"  OrderList="OrderE OrderF" >
                                <spouse>Jane</spouse>
                                <Order OrderID="OrderE"><OrderValue>55</OrderValue></Order>
                                <Order OrderID="OrderF"><OrderValue>55</OrderValue></Order>
                </Customer>
                <Customer CustomerID="C4"  OrderList="OrderG"  >
                                <spouse>Tim</spouse>
                                <Order OrderID="OrderG"><OrderValue>66</OrderValue></Order>
                        </Customer>
                <Customer CustomerID="C5"  >
                </Customer>
                <Customer CustomerID="C6" >
                </Customer>
                <Customer CustomerID="C7"  >
                </Customer>
</CustOrders:Customers>'

select @x.query(' declare namespace CustOrders="Customers"; 
 data(CustOrders:Customers/Customer[1]/@OrderList)[1] instance of xs:IDREF ? ') as XML_result

Limitazioni di implementazione

Limitazioni:

  • I tipi di sequenza schema-element() e schema-attribute() non sono supportati per il confronto all'operatore instance of.

  • Le sequenze complete, ad esempio (1,2) instance of xs:integer*, non sono supportate.

  • Quando si utilizza una forma del tipo di sequenza element() che specifica un nome di tipo, ad esempio element(ElementName, TypeName), è necessario qualificare il tipo con un punto interrogativo (?). Ad esempio, element(Title, xs:string?) indica che l'elemento potrebbe essere Null. SQL Server non supporta il rilevamento in fase di esecuzione della proprietà xsi:nil utilizzando instance of.

  • Se il valore in Expression viene da un elemento o un attributo tipizzato come unione, SQL Server può identificare solo il tipo primitivo dal quale deriva il tipo di valore, non il tipo derivato. Ad esempio, se si specifica un tipo statico (xs:integer | xs:string) per <e1>, la query seguente restituirà False.

    data(<e1>123</e1>) instance of xs:integer
    

    data(<e1>123</e1>) instance of xs:decimal tuttavia restituirà True.

  • Per i tipi di sequenza processing-instruction() e document-node() sono supportate solo forme senza argomenti. Ad esempio, processing-instruction() è consentito, ma processing-instruction('abc') non è consentito.

Operatore cast as

L'espressione cast as consente di convertire un valore in un tipo di dati specifico. Ad esempio:

          Expression cast as  AtomicType?

In SQL Server, dopo AtomicType è necessario il punto interrogativo (?). Ad esempio, come illustrato nella query seguente, "2" cast as xs:integer? converte il valore stringa in un valore integer:

declare @x xml
set @x=''
select @x.query('"2" cast as xs:integer?')

Nella query seguente, data() restituisce il valore tipizzato dell'attributo ProductModelID, un tipo stringa. L'operatore cast asconverte il valore in xs:integer.

WITH XMLNAMESPACES ('https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription' AS PD)
SELECT CatalogDescription.query('
   data(/PD:ProductDescription[1]/@ProductModelID) cast as xs:integer?
') as Result
FROM Production.ProductModel
WHERE ProductModelID = 19

L'utilizzo esplicito di data() non è necessario in questa query. L'espressione cast as esegue l'atomizzazione implicita sull'espressione di input.

Funzioni costruttore

È possibile utilizzare le funzioni costruttore del tipo atomico. Ad esempio, anziché utilizzare l'operatore cast as"2" cast as xs:integer?, è possibile utilizzare la funzione costruttore xs:integer(), come illustrato nell'esempio seguente:

declare @x xml
set @x=''
select @x.query('xs:integer("2")')

L'esempio seguente restituisce un valore xs:date uguale a 2000-01-01Z.

declare @x xml
set @x=''
select @x.query('xs:date("2000-01-01Z")')

È inoltre possibile utilizzare i costruttori per i tipi atomici definiti dall'utente. Ad esempio, se la raccolta di XML Schema associata al tipo di dati XML definisce un tipo semplice, è possibile utilizzare un costruttore myType() per ottenere la restituzione di un valore di quel tipo.

Limitazioni di implementazione

  • Le espressioni XQuery typeswitch, castable e treat non sono supportate.

  • cast as richiede un punto interrogativo (?) dopo il tipo atomico.

  • Il cast del tipo xs:QName non è supportato. Utilizzare expanded-QName.

  • xs:date, xs:time e xs:datetime richiedono un fuso orario, che è indicato da una Z.

    La query seguente ha esito negativo, perché il fuso orario non è specificato.

    DECLARE @var XML
    SET @var = ''
    SELECT @var.query(' <a>{xs:date("2002-05-25")}</a>')
    go
    

    Aggiungendo l'indicatore di fuso orario Z al valore, la query riesce.

    DECLARE @var XML
    SET @var = ''
    SELECT @var.query(' <a>{xs:date("2002-05-25Z")}</a>')
    go
    

    Risultato:

    <a>2002-05-25Z</a>