Expressions SequenceType (XQuery)

Dans XQuery, une valeur est toujours une séquence. Le type de la valeur est désigné par le terme « type de séquence ». Le type de séquence peut être utilisé dans une expression XQuery instance of. Vous utilisez la syntaxe SequenceType décrite dans la spécification XQuery lorsque vous devez faire référence à un type dans une expression XQuery.

Le nom de type atomique peut également être utilisé dans l'expression XQuery cast as. Dans SQL Server, les expressions XQuery instance of et cast as sur des expressions SequenceType sont partiellement prises en charge.

Opérateur instance of

L'opérateur instance of permet de déterminer le type dynamique ou d'exécution de la valeur de l'expression spécifiée. Exemple :

          Expression instance of SequenceType[Occurrence indicator]

L'opérateur instance of , l'Occurrence indicator, spécifie la cardinalité, le nombre d'éléments dans la séquence obtenue. Si cela n'est pas spécifié, il est supposé que la cardinalité est de 1. Dans SQL Server, seules l'indicateur d'occurrences de point d'interrogation (?) ) est pris en charge. L'indicateur d'occurrence ? indique que Expression peut renvoyer un élément, ou n'en renvoyer aucun. Si l'indicateur d'occurrence ? est défini, instance of renvoie True lorsque le type Expression correspond au SequenceType spécifié, que Expression renvoie un singleton ou une séquence vide.

Si l'indicateur d'occurrence ? n'est pas défini, sequence of renvoie True uniquement lorsque le type Expression correspond au Type spécifié et que Expression renvoie un singleton.

Remarque Les indicateurs d'occurrence de symbole plus (+) et d'astérisque (*) ne sont pas pris en charge dans SQL Server.

Les exemples ci-après illustrent l'utilisation de l'opérateur XQuery instance of.

Exemple A

L'exemple suivant crée une variable de type xml et spécifie une requête par rapport à celle-ci. L'expression de requête spécifie un opérateur instance of pour déterminer si le type dynamique de la valeur renvoyée par le premier opérande correspond au type spécifié dans le second opérande.

La requête suivante renvoie True, car la valeur 125 est une instance du type spécifiée, xs:integer :

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

La requête suivante renvoie True, car la valeur renvoyée par l'expression, /a[1], dans le premier opérande est un élément :

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

De même, instance of renvoie True dans la requête suivante, car le type de valeur de l'expression dans la première expression est un attribut :

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

Dans l'exemple suivant, l'expression data(/a[1] renvoie une valeur atomique typée sous la forme xdt:untypedAtomic. Par conséquent, l'opérateur instance of renvoie True.

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

Dans la requête suivante, l'expression data(/a[1]/@attrA renvoie une valeur atomique non typée. Par conséquent, l'opérateur instance of renvoie True.

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

Exemple B

Dans cet exemple, vous interrogez une colonne XML typée de l'exemple de base de données AdventureWorks2008R2. La collection de schémas XML associée à la colonne interrogée fournit les informations de définition de type.

Dans l'expression, data() renvoie la valeur typée de l'attribut ProductModelID dont le type est xs:string, suivant le schéma associé à la colonne. Par conséquent, l'opérateur instance of renvoie 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

Pour plus d'informations, consultez Comparaison du XML typé et du XML non typé. Pour plus d'informations sur la collection de schémas XML associée à la colonne CatalogDescription, consultez À propos de la colonne xml ProductModel.CatalogDescription.

Les requêtes suivantes utilisent l'expression booléenne instance of pour déterminer si l'attribut LocationID est de type 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 requête suivante porte sur la colonne XML typée CatalogDescription. La collection de schémas XML associée à cette colonne fournit les informations de définition de type. Pour plus d'informations sur la collection de schémas XML, consultez À propos de la colonne xml ProductModel.CatalogDescription.

La requête utilise le test element(ElementName, ElementType?) dans l'expression instance of pour vérifier que /PD:ProductDescription[1] renvoie un nœud d'élément d'un nom et d'un type spécifiques.

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 requête renvoie True.

Exemple C

Lors de l'utilisation de types d'union, l'expression instance of dans SQL Server présente une limite : en particulier, lorsque le type d'un élément ou d'un attribut est un type d'union, instance of peut ne pas déterminer le type exact. De ce fait, une requête renvoie False, sauf si le type atomique utilisé dans le type de séquence est le parent le plus élevé du type réel de l'expression dans la hiérarchie simpleType. En d'autres termes, les types atomiques spécifiés dans le type de séquence doivent être un enfant direct de anySimpleType. Pour plus d'informations sur la hiérarchie des types, consultez Règles de conversion de types dans XQuery.

L'exemple de requête ci-après effectue les opérations suivantes :

  • Créer une collection de schémas XML dans laquelle est défini un type d'union, tel qu'un type integer ou string.

  • Déclarer une variable xml typée à l'aide de la collection de schémas XML.

  • Affecter un exemple d'instance XML à la variable.

  • Interroger la variable pour illustrer le comportement de l'opérateur instance of lors de l'utilisation d'un type d'union.

Voici la requête :

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 requête suivante renvoie False, car le type de séquence spécifié dans l'expression instance of n'est pas le parent le plus élevé du type réel de l'expression spécifiée. En d'autres termes, la valeur de <TestElement> est un type integer. Le parent le plus élevé est xs:decimal. Toutefois, il n'est pas spécifié comme second opérande de l'opérateur 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

Étant donné que le parent le plus élevé de xs:integer est xs:decimal, la requête renvoie True si vous la modifiez et que vous y spécifiez xs:decimal comme type de séquence.

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

Exemple D

Dans cet exemple, vous créez une collection de schémas XML puis vous l'utilisez pour définir le type d'une variable xml. La variable xml typée est ensuite interrogée pour illustrer la fonctionnalité de l'opérateur instance of.

La collection de schémas XML suivante définit un type simple, myType, et un élément, <root>, de type 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

Maintenant, créez une variable xml typée et interrogez-la :

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

Étant donné que le type myType dérive par restriction d'un type varchar défini dans le schéma sqltypes, instance of renvoie également 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

Exemple E

Dans l'exemple suivant, l'expression extrait l'une des valeurs de l'attribut IDREFS et utilise l'opérateur instance of pour déterminer si la valeur est de type IDREF. L'exemple effectue les opérations suivantes :

  • Créer une collection de schémas XML dans laquelle l'élément <Customer> possède un attribut de type IDREFS OrderList et l'élément <Order> détient un attribut de type ID OrderID.

  • Créer une variable xml typée et lui affecter un exemple d'instance XML.

  • Spécifier une requête par rapport à la variable. L'expression de requête extrait la première valeur d'ID de commande de l'attribut OrderList de type IDRERS du premier <Customer>. La valeur extraite est de type IDREF. Par conséquent, l'opérateur instance of renvoie 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

Limites de la mise en œuvre

Les limites sont les suivantes :

  • Les types de séquence schema-element() et schema-attribute() ne sont pas pris en charge pour la comparaison avec l'opérateur instance of.

  • Les séquences complètes, telles que (1,2) instance of xs:integer*, ne sont pas prises en charge.

  • Lorsque la forme du type de séquence element() spécifie un nom de type, tel que element(ElementName, TypeName), vous devez qualifier le type avec un point d'interrogation (?). Par exemple, element(Title, xs:string?) indique que l'élément peut être NULL. SQL Server ne prend pas en charge la détection au moment de l'exécution de la propriété xsi:nil à l'aide de l'opérateur instance of.

  • Si la valeur de Expression provient d'un élément ou d'un attribut typé en tant qu'union, SQL Server peut uniquement identifier le type de primitive, non dérivé, duquel le type de la valeur a été dérivé. Par exemple, si <e1> est défini de manière à posséder le type statique (xs:integer | xs:string), la syntaxe ci-après renvoie False.

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

    Toutefois, data(<e1>123</e1>) instance of xs:decimal renvoie True.

  • Dans le cas des types de séquence processing-instruction() et document-node(), seules les formes sans arguments sont autorisées. Par exemple, processing-instruction() est autorisé, contrairement à processing-instruction('abc').

Opérateur cast as

L'expression cast as permet de convertir une valeur en un type de données spécifique. Exemple :

          Expression cast as  AtomicType?

Dans SQL Server, le point d'interrogation (?) est obligatoire après AtomicType. Par exemple, comme le montre la requête suivante, "2" cast as xs:integer? convertit la value de chaîne à un entier :

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

Dans la requête suivante, data() renvoie la valeur typée de l'attribut ProductModelID, en l'occurrence un type chaîne. L'opérateur cast as convertit la valeur en 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'utilisation explicite de data() n'est pas requise dans cette requête. L'expression cast as effectue une atomisation implicite sur l'expression d'entrée.

Fonctions constructeur

Vous pouvez utiliser les fonctions constructeur de type atomique. Ainsi, au lieu d'utiliser l'opérateur cast as, "2" cast as xs:integer?, vous pouvez recourir à la fonction constructeur xs:integer(), comme le montre l'exemple suivant :

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

L'exemple suivant renvoie une valeur xs:date égale à 2000-01-01Z.

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

Vous pouvez également utiliser des constructeurs pour les types atomiques définis par l'utilisateur. Par exemple, si la collection de schémas XML associée au type de données XML définit un type simple, un constructeur myType() peut être utilisé pour renvoyer une valeur de ce type.

Limites de la mise en œuvre

  • Les expressions XQuery typeswitch, castable et treat ne sont pas prises en charge.

  • L'opérateur cast as requiert un point d'interrogation (?) après le type atomique.

  • xs:QName n'est pas pris en charge comme type pour la conversion. Utilisez plutôt expanded-QName.

  • xs:date, xs:time et xs:datetime requièrent un fuseau horaire, ce que signale le caractère Z.

    La requête suivante échoue, car le fuseau horaire n'est pas spécifié.

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

    Si vous ajoutez l'indicateur de fuseau horaire Z à la valeur, la requête fonctionne.

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

    Voici le résultat obtenu :

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