Instructions pour l'utilisation des méthodes de type de données XML

Cette rubrique décrit comment utiliser les méthodes de type de données xml.

Instruction PRINT

Les méthodes de type de données xml ne peuvent pas être utilisées dans l'instruction PRINT, comme l'illustre l'exemple ci-dessous. Les méthodes de type de données xml sont traitées comme des sous-requêtes et les sous-requêtes ne sont pas autorisées dans l'instruction PRINT. Par conséquent, l'exemple ci-dessous retourne une erreur :

DECLARE @x xml
SET @x = '<root>Hello</root>'
PRINT @x.value('/root[1]', 'varchar(20)') -- will not work because this is treated as a subquery (select top 1 col from table) 

Une solution consiste à attribuer le résultat de la méthode value() à une variable de type xml, puis à spécifier la variable dans la requête.

DECLARE @x xml
DECLARE @c varchar(max)
SET @x = '<root>Hello</root>'
SET @c = @x.value('/root[1]', 'varchar(11)')
PRINT @c                                                      

Clause GROUP BY

Les méthodes de type de données xml sont traitées de manière interne comme des sous-requêtes. Comme la clause GROUP BY requiert une valeur scalaire et n'autorise pas les agrégats et les sous-requêtes, vous ne pouvez pas spécifier les méthodes de type de données xml dans la clause GROUP BY. Une solution consiste à appeler une fonction définie par l'utilisateur qui utilise des méthodes XML en son sein.

Signalement des erreurs

Lors du signalement des erreurs, les méthodes de type de données xml génèrent une erreur unique au format suivant :

Msg errorNumber, Level levelNumber, State stateNumber:
XQuery [database.table.method]: description_of_error

Exemple :

Msg 2396, Level 16, State 1:
XQuery [xmldb_test.xmlcol.query()]: Attribute may not appear outside of an element

Vérifications des singletons

Les étapes d'emplacement, les paramètres de fonction et les opérateurs qui réclament des singletons renverront une erreur lorsque le compilateur n'arrive pas à savoir si la présence d'un singleton est garantie lors de l'exécution. Ce problème se produit souvent avec des données non typées. Par exemple, la recherche d'un attribut exige un élément parent unique. Un nombre ordinal qui sélectionne un nœud parent unique suffit. L'évaluation d'une combinaison node()-value() pour extraire les valeurs d'attribut ne requiert pas de spécification ordinale, comme le montre l'exemple suivant.

Exemple : Singleton connu

Dans cet exemple, la méthode nodes() génère une ligne distincte pour chaque élément <book>. La méthode value() qui est évaluée sur un nœud <book> extrait la valeur de @genre qui, puisqu'il s'agit d'un attribut, est un singleton.

SELECT nref.value('@genre', 'varchar(max)') LastName
FROM   T CROSS APPLY xCol.nodes('//book') AS R(nref)

Le schéma XML sert à vérifier le type en cas de code XML typé. Si un nœud est spécifié en tant que singleton dans le schéma XML, le compilateur utilise cette information et aucune erreur ne se produit. Dans le cas contraire, un nombre ordinal sélectionnant un nœud unique est requis. En particulier, l'emploi de l'axe descendant-or-self (//), comme dans /book//title, fait perdre l'inférence de cardinalité de singleton de l'élément <title>, même si le schéma XML le déclare en tant que tel. Vous devez par conséquent le réécrire sous la forme (/book//title)[1].

Il faut toujours garder à l'esprit la différence qui existe entre //first-name[1] et (//first-name)[1] en cas de vérification du type. Le premier renvoie une séquence de nœuds <first-name> où chaque nœud est le nœud <first-name> le plus à gauche de ses frères. Le dernier renvoie le premier nœud <first-name> singleton dans l'ordre du document de l'instance XML.

Exemple : Utilisation de value()

La requête suivante porte sur une colonne non typée XML et génère une erreur de compilation statique. En effet, value() attend un nœud singleton comme premier argument et le compilateur ne peut pas déterminer si un seul et unique nœud <last-name> sera rencontré lors de l'exécution :

SELECT xCol.value('//author/last-name', 'nvarchar(50)') LastName
FROM   T

L'exemple suivant vous montre une solution à envisager :

SELECT xCol.value('//author/last-name[1]', 'nvarchar(50)') LastName
FROM   T

Toutefois, cette solution ne permet pas de remédier à l'erreur car il peut y avoir plusieurs nœuds <author> dans chaque instance XML. Réécrit ainsi, l'exemple fonctionne :

SELECT xCol.value('(//author/last-name/text())[1]', 'nvarchar(50)') LastName
FROM   T

Cette requête renvoie la valeur du premier élément <last-name> de chaque instance XML.