Système de types (XQuery)
XQuery est un langage fortement typé pour les types de schéma et un langage faiblement typé pour les données non typées. Les types prédéfinis de XQuery incluent les suivants :
- Types intégrés de schéma XML dans l'espace de noms http://www.w3.org/2001/XMLSchema.
- Types définis dans l'espace de noms http://www.w3.org/2004/07/xpath-datatypes.
Cette rubrique décrit également les éléments suivants :
- La valeur typée par rapport à la valeur de chaîne d'un nœud.
- La fonction data (XQuery) et la fonction string (XQuery).
- Mise en correspondance du type de séquence retourné par une expression.
Types intégrés de schéma XML
Les types intégrés de schéma XML possèdent un préfixe d'espace de noms prédéfini, xs. Certains de ces types incluent xs:integer et xs:string. Tous ces types intégrés sont pris en charge. Vous pouvez utiliser ces types lorsque vous créez une collection de schémas XML.
Lorsque vous interrogez des données XML typées, le type statique et dynamique des nœuds est déterminé par la collection de schémas XML associée à la colonne ou à la variable sur laquelle porte la requête. Pour plus d'informations sur les types statiques et dynamiques, consultez Contexte des expressions et évaluation des requêtes (XQuery). Par exemple, la requête ci-dessous est spécifiée sur une colonne xml typée (Instructions
). L'expression utilise instance of
pour vérifier que la valeur typée de l'attribut LotSize
retourné est de type 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
Cette information de type est fournie par la collection de schémas XML associée à la colonne. Pour plus d'informations, consultez Représentation du type de données xml dans la base de données AdventureWorks.
Types définis dans l'espace de noms des types de données XPath
Les types définis dans l'espace de noms http://www.w3.org/2004/07/xpath-datatypes ont le préfixe prédéfini xdt. Les règles suivantes s'appliquent à ces types :
- Vous ne pouvez pas utiliser ces types lorsque vous créez une collection de schémas XML. Ces types sont utilisés dans le système de types XQuery, pour les types statiques. Vous pouvez effectuer un cast vers les types atomiques, par exemple, xdt:untypedAtomic, dans l'espace de noms xdt.
- Lors de l'interrogation de données XML non typées, le type statique et dynamique des nœuds d'élément est xdt:untyped, et le type des valeurs d'attribut est xdt:untypedAtomic. Le résultat d'une méthode query() génère des données XML non typées. Cela signifie que les nœuds XML sont retournés comme xdt:untyped et xdt:untypedAtomic, respectivement.
- Les types xdt:dayTimeDuration et xdt:yearMonthDuration ne sont pas pris en charge.
Dans l'exemple suivant, la requête est spécifiée sur une variable de type XML non typé. L'expression, data(/a[1]
), retourne une séquence d'une valeur atomique. La fonction data()
retourne la valeur typée de l'élément <a>
. Comme les données XML interrogées sont non typées, le type de la valeur retournée est xdt:untypedAtomic
. Par conséquent, instance of
retourne true.
DECLARE @x xml
SET @x='<a>20</a>'
SELECT @x.query( 'data(/a[1]) instance of xdt:untypedAtomic' )
Au lieu de récupérer la valeur typée, l'expression (/a[1]
) dans l'exemple ci-dessous retourne une séquence d'un élément, l'élément <a>
. L'expression instance of
utilise le test d'élément pour vérifier que la valeur retournée par l'expression est un nœud d'élément de 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()')
Remarque : |
---|
Lorsque vous interrogez une instance XML typée et que l'expression de requête inclut l'axe parent, le type statique d'information des nœuds résultants n'est plus disponible. Toutefois, le type dynamique est encore associé aux nœuds. |
Valeur typée par rapport à valeur de chaîne
Chaque nœud possède une valeur typée et une valeur de chaîne. Pour les données XML typées, le type de la valeur typée est fourni par la collection de schémas XML associée à la colonne ou à la variable sur laquelle porte la requête. Pour les données XML non typées, le type de la valeur typée est xdt:untypedAtomic.
Vous pouvez utiliser la fonction data() ou string() pour récupérer la valeur d'un nœud :
- La fonction de données retourne la valeur typée d'un nœud.
- La fonction de chaîne retourne la valeur de chaîne du nœud.
Dans la collection de schémas XML ci-dessous, l'élément <root
> du type entier est défini :
CREATE XML SCHEMA COLLECTION SC AS N'
<schema xmlns="http://www.w3.org/2001/XMLSchema">
<element name="root" type="integer"/>
</schema>'
GO
Dans l'exemple ci-dessous, l'expression commence par récupérer la valeur typée de /root[1]
et lui ajoute 3
.
DECLARE @x xml(SC)
SET @x='<root>5</root>'
SELECT @x.query('data(/root[1]) + 3')
Dans l'exemple suivant, l'expression échoue, car string(/root[1])
dans l'expression retourne une valeur de type de chaîne. Cette valeur est alors transmise à un opérateur arithmétique qui accepte uniquement les valeurs de type numérique comme opérandes.
-- 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')
L'exemple ci-dessous calcule le total des attributs LaborHours
. La fonction data()
récupère les valeurs typées des attributs LaborHours
à partir de tous les éléments <Location
> pour un modèle de produit. Selon le schéma XML associé à la colonne Instruction
, LaborHours
est de type 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
Cette requête retourne un résultat égal à 12,75.
Remarque : |
---|
L'utilisation explicite de la fonction data() dans cet exemple est fournie à titre d'illustration uniquement. Si elle n'est pas spécifiée, sum() applique implicitement la fonction data() pour extraire les valeurs typées des nœuds. |
Mise en correspondance du type de séquence
Une valeur d'expression XQuery est toujours une séquence de zéro élément ou plus. Une élément peut être soit une valeur atomique, soit un nœud. Le type de séquence fait référence à la possibilité de mettre en correspondance le type de séquence retourné par une expression de requête avec un type spécifique. Exemple :
- Si la valeur d'expression est atomique, vous voudrez peut-être savoir s'il s'agit d'un type entier, décimal ou chaîne.
- Si la valeur d'expression est un nœud XML, vous voudrez peut-être savoir s'il s'agit d'un nœud de commentaire, d'un nœud d'instruction de traitement ou d'un nœud de texte.
- Vous voudrez peut-être savoir si l'expression retourne un élément XML ou un nœud d'attribut d'un nom et d'un type spécifiques.
Vous pouvez utiliser l'opérateur booléen instance of
dans la mise en correspondance de type de séquence. Pour plus d'informations sur l'expression instance of
, consultez Expressions SequenceType (XQuery).
Comparaison du type de valeur atomique retourné par une expression
Si une expression retourne une séquence de valeurs atomiques, vous pouvez être amené à rechercher le type de la valeur dans la séquence. Les exemples ci-dessous illustrent comment utiliser la syntaxe de type de séquence pour évaluer le type de valeur atomique retourné par une expression.
Exemple A
Le type de séquence empty() peut être utilisé dans une expression de type de séquence pour déterminer si la séquence retournée par l'expression spécifiée est une séquence vide.
Dans l'exemple ci-dessous, le schéma XML autorise l'élément <root
> à être annulé :
CREATE XML SCHEMA COLLECTION SC AS N'
<schema xmlns="http://www.w3.org/2001/XMLSchema">
<element name="root" nillable="true" type="byte"/>
</schema>'
GO
À présent, si une instance XML typée spécifie une valeur pour l'élément <root
>, instance of empty()
retourne False.
DECLARE @var XML(SC1)
SET @var = '<root>1</root>'
-- The following returns False
SELECT @var.query('data(/root[1]) instance of empty() ')
GO
Si l'élément <root
> est annulé dans l'instance, sa valeur est une séquence vide et instance of empty()
retourne 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
Exemple B
Parfois, vous voudrez peut-être évaluer le type de séquence retourné par une expression avant le traitement. Par exemple, vous pouvez disposer d'un schéma XML dans lequel un nœud est défini comme type d'union. Dans l'exemple ci-dessous, le schéma XML dans la collection définit l'attribut a
comme un type d'union dont la valeur peut être de type décimal ou chaîne.
-- 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
Avant de traiter une instance XML typée, vous voudrez peut-être connaître le type de la valeur de l'attribut a
. Dans l'exemple ci-dessous, la valeur de l'attribut a
est un type décimal. Par conséquent, , instance of xs:decimal
retourne True.
DECLARE @var XML(SC)
SET @var = '<root a="2.5"/>'
SELECT @var.query('data((/root/@a)[1]) instance of xs:decimal')
GO
À présent, changez la valeur de l'attribut a
en type de chaîne. instance of xs:string
retournera True.
DECLARE @var XML(SC)
SET @var = '<root a="Hello"/>'
SELECT @var.query('data((/root/@a)[1]) instance of xs:string')
GO
Exemple C
Cet exemple illustre l'effet de la cardinalité dans une expression de séquence. Le schéma XML ci-dessous définit un élément <root
> de type octet qui accepte la valeur 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
Dans la requête ci-dessous, comme l'expression retourne un singleton de type octet, instance of
retourne True.
DECLARE @var XML(SC)
SET @var = '<root>111</root>'
SELECT @var.query('data(/root[1]) instance of xs:byte ')
GO
Si vous rendez nul l'élément <root
>, sa valeur est une séquence vide. Cela signifie que l'expression /root[1]
retourne une séquence vide. Par conséquent, instance of xs:byte
retourne False. Notez que la cardinalité par défaut dans ce cas est 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
Si vous spécifiez la cardinalité en ajoutant l'indicateur d'occurrence (?
), l'expression de séquence retourne 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
Notez que le test dans une expression de type de séquence s'effectue en deux phases :
- En premier lieu, le test détermine si le type d'expression correspond au type spécifié.
- Si tel est le cas, le test détermine alors si le nombre d'éléments retournés par l'expression correspond à l'indicateur d'occurrence spécifié.
Si les deux conditions sont respectées, l'expression instance of
retourne True.
Exemple D
Dans l'exemple ci-dessous, une requête est spécifiée sur une colonne Instructions de type xml dans la base de données AdventureWorks. Il s'agit d'une colonne XML typée car un schéma lui est associé. Pour plus d'informations, consultez Représentation du type de données xml dans la base de données AdventureWorks. Le schéma XML définit l'attribut LocationID
du type entier. Par conséquent, dans l'expression de séquence, instance of xs:integer?
retourne 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
Comparaison du type de nœud retourné par une expression
Si une expression retourne une séquence de nœuds, vous pouvez être amené à rechercher le type du nœud dans la séquence. Les exemples ci-dessous illustrent comment utiliser la syntaxe de type de séquence pour évaluer le type de nœud retourné par une expression. Vous pouvez utiliser les types de séquence suivants :
- item() – Met en correspondance tous les éléments de la séquence.
- node() – Détermine si la séquence est un nœud.
- processing-instruction() – Détermine si l'expression retourne une instruction de traitement.
- comment() – Détermine si l'expression retourne un commentaire.
- document-node() – Détermine si l'expression retourne un nœud de document.
Les exemples ci-dessous illustrent ces types de séquence.
Exemple A
Dans cet exemple, plusieurs requêtes sont exécutées sur une variable XML non typée. Ces requêtes illustrent l'utilisation de types de séquence.
DECLARE @var XML
SET @var = '<?xml-stylesheet href="someValue" type="text/xsl" ?>
<root>text node
<!-- comment 1 -->
<a>Data a</a>
<!-- comment 2 -->
</root>'
Dans la première requête, l'expression retourne la valeur typée de l'élément <a
>. Dans la seconde requête, l'expression retourne l'élément <a
>. Les deux sont des éléments. Par conséquent, les deux requêtes retournent True.
SELECT @var.query('data(/root[1]/a[1]) instance of item()')
SELECT @var.query('/root[1]/a[1] instance of item()')
Toutes les expressions XQuery des trois requêtes ci-dessous retournent le nœud d'élément enfant de l'élément <root
>. Par conséquent, l'expression de type de séquence, instance of node()
, retourne True et les deux autres expressions, instance of text()
et instance of document-node()
, retournent 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()')
Dans la requête ci-dessous, l'expression instance of document-node()
retourne True, car le parent de l'élément <root
> est un nœud de document.
SELECT @var.query('(/root/..)[1] instance of document-node()') -- true
Dans la requête ci-dessous, l'expression récupère le premier nœud de l'instance XML. Comme il s'agit d'un nœud d'instruction de traitement, l'expression instance of processing-instruction()
retourne True.
SELECT @var.query('(/node())[1] instance of processing-instruction()')
Limitations d'implémentation
Les limitations spécifiques sont répertoriées ci-dessous :
- La syntaxe document-node() avec un type de contenu n'est pas prise en charge.
- La syntaxe processing-instruction(name) n'est pas prise en charge.
Test d'élément
Un test d'élément permet de mettre en correspondance le nœud d'élément retourné par une expression avec un nœud d'élément avec un nom et un type spécifiques. Vous pouvez utiliser les tests d'éléments :
element ()
element(ElementName)
element(ElementName, ElementType?)
element(*, ElementType?)
Test d'attribut
Le test d'attribut détermine si l'attribut retourné par une expression est un nœud d'attribut. Vous pouvez utiliser les tests d'attributs :
attribute()
attribute(AttributeName)
attribute(AttributeName, AttributeType)
Exemples de test
Les exemples ci-dessous illustrent des scénarios dans lesquels des tests d'éléments et d'attributs sont utiles.
Exemple A
Le schéma XML ci-dessous définit le type complexe CustomerType
, dans lequel les éléments <firstName
> et <lastName
> sont facultatifs. Pour une instance XML spécifiée, vous pouvez être amené à déterminer si un prénom existe pour un client donné.
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 requête ci-dessous utilise une expression instance of element (firstName)
pour déterminer si le premier élément enfant de <customer
> est un élément du nom de <firstName
>. Si tel est le cas, elle retourne True.
SELECT @var.query('declare namespace x="myNS";
(/x:customer/*)[1] instance of element (firstName)')
GO
Si vous supprimez l'élément <firstName
> de l'instance, la requête retourne False.
Vous pouvez également utiliser :
La syntaxe de type de séquence
element(ElementName, ElementType?)
, comme cela est illustré dans la requête ci-dessous. Elle met en correspondance un nœud d'élément nul ou non nul dont le nom estfirstName
et dont le type estxs:string
.SELECT @var.query('declare namespace x="myNS"; (/x:customer/*)[1] instance of element (firstName, xs:string?)')
La syntaxe de type de séquence
element(*, type?)
, comme cela est illustré dans la requête ci-dessous. Elle met en correspondance le nœud d'élément si son type estxs:string
, quel que soit son nom.SELECT @var.query('declare namespace x="myNS"; (/x:customer/*)[1] instance of element (*, xs:string?)') GO
Exemple B
L'exemple ci-dessous illustre comment déterminer si le nœud retourné par une expression est un nœud d'élément avec un nom spécifique. Il utilise le test element().
Dans l'exemple ci-dessous, les deux éléments <Customer
> de l'instance XML qui font l'objet de la requête sont de deux types différents, CustomerType
et SpecialCustomerType
. Supposons que vous voulez connaître le type de l'élément <Customer
> retourné par l'expression. La collection de schémas XML suivante définit les types CustomerType
et 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
Cette collection de schémas XML est utilisée pour créer une variable xml typée. L'instance XML attribuée à cette variable possède deux éléments <customer
> de deux types différents. Le premier élément est de type CustomerType
et le second élément de type 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>'
Dans la requête ci-dessous, l'expression instance of element (*, x:SpecialCustomerType ?)
retourne False, car l'expression retourne le premier élément client qui n'est pas de type SpecialCustomerType
.
SELECT @var.query('declare namespace x="myNS";
(/x:customer)[1] instance of element (*, x:SpecialCustomerType ?)')
Si vous modifiez l'expression de la requête précédente et récupérez le second élément <customer
> (/x:customer)[2]
), instance of
retournera True.
Exemple C
Cet exemple utilise le test d'attribut. Le schéma XML ci-dessous définit le type complexe CustomerType avec les attributs CustomerID et Age. L'attribut Age est facultatif. Pour une instance XML spécifique, vous voudrez peut-être déterminer si l'attribut Age est présent dans l'élément <customer
>.
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 requête ci-dessous retourne True, car il existe un nœud d'attribut du nom Age
dans l'instance XML sur laquelle porte la requête. Le test d'attribut attribute(Age)
est utilisé dans cette expression. Comme les attributs ne sont pas ordonnés, la requête utilise l'expression FLWOR pour récupérer tous les attributs et tester ensuite chaque attribut à l'aide de l'expression instance of
. L'exemple commence par créer une collection de schémas XML pour créer une variable xml typée.
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
Si vous supprimez l'attribut facultatif Age
de l'instance, la requête précédente retournera False.
Vous pouvez spécifier le nom et le type d'attribut (attribute(name,type)
) dans le test d'attribut.
SELECT @var.query('declare namespace x="myNS";
FOR $i in /x:customer/@*
RETURN
IF ($i instance of attribute (Age, xs:integer)) THEN
"true"
ELSE
()')
Une autre méthode consiste à spécifier la syntaxe de type de séquence attribute(*, type)
. Cela met en correspondance le nœud d'attribut si le type d'attribut correspond au type spécifié, quel que soit le nom.
Limitations d'implémentation
Les limitations spécifiques sont répertoriées ci-dessous :
- Dans le test d'élément, le nom du type doit être suivi de l'indicateur d'occurrence (?).
- element(ElementName, TypeName) n'est pas pris en charge.
- element(*, TypeName) n'est pas pris en charge.
- schema-element() n'est pas pris en charge.
- schema-attribute(AttributeName) n'est pas pris en charge.
- Les requêtes explicites pour xsi:type ou xsi:nil ne sont pas prises en charge.
Voir aussi
Concepts
Expressions SequenceType (XQuery)
Concepts de base de XQuery
Autres ressources
Utilisation du Générateur de profils SQL Server