Types de données XPath (SQLXML 4.0)
Microsoft SQL Server, XPath et XML Schema (XSD) sont dotés de types de données très différents. Par exemple, XPath n'affiche aucun type de données integer ou date tandis que SQL Server et XSD en possèdent un grand nombre. XSD utilise une précision à la nanoseconde pour les valeurs temporelles ; SQL Server affiche au maximum une précision de 1/300ème de seconde. Par conséquent, le mappage d'un type de données à un autre n'est pas toujours possible. Pour plus d'informations sur le mappage des types de données SQL Server aux types de données XSD, consultez Forçages de type de données et annotation sql:datatype (SQLXML 4.0).
XPath possède trois types de données : string, number et boolean. Le type de données number est toujours une valeur à virgule flottante double précision IEEE 754. Le type de données SQL Server float(53) est le plus proche du type de données XPath number. Toutefois, le type float(53) n'est pas exactement une valeur IEEE 754. Par exemple, ni la valeur NaN (Not-a-Number,), ni une valeur infinie n'est employée. Toute tentative de conversion d'une chaîne non numérique en type number et de division par zéro entraîne une erreur.
Conversions XPath
Lorsque vous utilisez une requête XPath, telle que OrderDetail[@UnitPrice > "10.0"], les conversions de type de données implicites et explicites peuvent modifier la signification de la requête de manière subtile. Par conséquent, il est primordial de comprendre la manière dont les types de données Xpath sont implémentés. Les recommandations concernant le langage Xpath (document « XML Path Language (XPath) version 1.0 W3C Proposed Recommendation » du 8 octobre 1999) peuvent être consultées sur le site Web du consortium W3C à l'adresse suivante : http://www.w3.org/TR/1999/PR-xpath-19991008.html.
Les opérateurs XPath sont divisés en quatre catégories :
Opérateurs booléens (et, ou)
Opérateurs relationnels (<, >, <=, >=)
Opérateurs d'égalité (=, !=)
Opérateurs arithmétiques (+, -, *, div, mod)
Chaque catégorie d'opérateur convertit ses opérandes de manière distincte. Les opérateurs XPath convertissent implicitement leurs opérandes si cela est nécessaire. Les opérateurs arithmétiques convertissent leurs opérandes en type number et génèrent une valeur numérique. Les opérateurs booléens convertissent leurs opérandes en boolean et génèrent une valeur booléenne. Les opérateurs relationnels et d'égalité génèrent une valeur booléenne. Toutefois, ils suivent des règles de conversion différentes en fonction des types de données d'origine de leurs opérandes comme le montre le tableau ci-après.
Opérande |
Opérateur relationnel |
Opérateur d'égalité |
---|---|---|
Les deux opérandes sont des éléments node-set. |
TRUE si et uniquement s'il existe un nœud dans un jeu et un nœud dans le deuxième jeu justifiant que la comparaison de leurs valeurs string soit TRUE. |
Idem. |
L'un est un élément node-set, l'autre est de type string. |
TRUE si et uniquement s'il existe un nœud dans l'élément node-set de sorte que, en cas de conversion en type number, sa comparaison avec la valeur string convertie en number est TRUE. |
TRUE si et uniquement s'il existe un nœud dans l'élément node-set de sorte que, en cas de conversion en type string, sa comparaison avec la valeur string est TRUE. |
L'un est un élément node-set, l'autre est de type number. |
TRUE si et uniquement s'il existe un nœud dans l'élément node-set de sorte que, en cas de conversion en type number, sa comparaison avec la valeur number est TRUE. |
Idem. |
L'un est un élément node-set, l'autre est de type boolean. |
TRUE si et uniquement s'il existe un nœud dans l'élément node-set de sorte que, en cas de conversion en type boolean, puis en type number, sa comparaison avec la valeur boolean convertie en number est TRUE. |
TRUE si et uniquement s'il existe un nœud dans l'élément node-set de sorte que, en cas de conversion en type boolean, sa comparaison avec la valeur boolean est TRUE. |
Ni l'un ni l'autre n'est un élément node-set. |
Convertissez les deux opérandes en type number, puis comparez-les. |
Convertissez les deux opérandes en un type commun, puis comparez-les. Convertissez en type boolean si l'une des valeurs est de type boolean, en number si l'une des valeurs est de type number ; sinon, effectuez une conversion en type string. |
[!REMARQUE]
Parce que les opérateurs relationnels XPath convertissent toujours leurs opérandes en number, les comparaisons de valeurs string ne sont pas possibles. Pour inclure des comparaisons de date, SQL Server 2000 propose la variante suivante par rapport à la recommandation XPath : lorsqu'un opérateur relationnel compare une valeur string à une autre valeur string, un élément node-set à une valeur string, ou deux éléments node-set à valeur de chaîne entre eux, une comparaison de la valeur string (et non une comparaison de number) a lieu.
Conversions des éléments node-set
Les conversions des éléments node-set ne sont pas toujours intuitives. Un élément node-set est converti en type string par extraction de la valeur de chaîne du premier nœud du jeu uniquement. Pour être converti en type number, un élément node-set est d'abord converti en type string, puis le type string est converti en type number. Pour convertir un élément node-set en type boolean, vous devez d'abord le tester pour vérifier s'il existe.
[!REMARQUE]
SQL Server ne procède à aucune sélection positionnelle sur les éléments node-set : par exemple, la requête XPath Customer[3] désigne le troisième client ; ce type de sélection positionnelle n'est pas pris en charge dans SQL Server. Par conséquent, les conversions d'élément node-set en string ou d'élément node-set en number, telles que décrites dans la recommandation XPath, ne sont pas implémentées. SQL Server utilise une sémantique « quelconque » partout où la recommandation XPath spécifie la « première » sémantique. Par exemple, d'après la recommandation XPath du consortium W3C, la requête XPath Order[OrderDetail/@UnitPrice > 10.0] sélectionne les commandes dont le premier élément OrderDetail affiche une valeur UnitPrice supérieure à 10.0. Dans SQL Server, cette requête XPath sélectionne les commandes dotées de n'importe quel élément OrderDetail avec une valeur UnitPrice supérieure à 10.0.
La conversion en valeur boolean implique un test de vérification d'existence ; la requête XPath Products[@Discontinued=true()] équivaut donc à l'expression SQL « Products.Discontinued is not null » et non à l'expression SQL « Products.Discontinued = 1 ». Pour que la requête équivaille à la dernière expression SQL, convertissez avant tout l'élément node-set en type non boolean, tel que number. Par exemple, Products[number(@Discontinued) = true()].
Du fait que la plupart des opérateurs sont définis pour être vrais (TRUE) s'ils le sont pour un nœud quelconque ou l'un des nœuds de l'élément node-set, ces opérations prennent toujours la valeur FALSE si l'élément node-set est vide. Ainsi donc, si A est vide, A = B et A != B ont tous les deux la valeur FALSE et not(A=B) et not(A!=B) ont la valeur TRUE.
En règle générale, un attribut ou un élément mappé à une colonne existe si la valeur de cette colonne dans la base de données n'est pas null. Les éléments mappés aux lignes existent si tous leurs enfants existent.
[!REMARQUE]
Les éléments annotés avec is-constant existent toujours. Par conséquent, les prédicats XPath ne peuvent être utilisés dans des éléments is-constant.
Lorsque vous convertissez un élément node-set en type string ou number, son type XDR (le cas échéant) est examiné dans le schéma annoté et utilisé pour déterminer la conversion requise.
Mappage des types de données XDR et XPath
Comme l'illustre le tableau ci-dessous, le type de données XPath d'un nœud est extrait du type de données XDR dans le schéma (le nœud EmployeeID est utilisé à des fins d'illustration).
Type de données XDR |
Équivalent Type de données XPath |
Conversion SQL Server utilisée |
---|---|---|
Nonebin.base64bin.hex |
N/A |
NoneEmployeeID |
boolean |
boolean |
CONVERT(bit, EmployeeID) |
number, int, float,i1, i2, i4, i8,r4, r8ui1, ui2, ui4, ui8 |
number |
CONVERT(float(53), EmployeeID) |
id, idref, idrefsentity, entities, enumerationnotation, nmtoken, nmtokens, chardate, Timedate, Time.tz, string, uri, uuid |
string |
CONVERT(nvarchar(4000), EmployeeID, 126) |
fixed14.4 |
N/A (aucun type de données XPath n'équivaut au type de données XDR fixed14.4) |
CONVERT(money, EmployeeID) |
date |
string |
LEFT(CONVERT(nvarchar(4000), EmployeeID, 126), 10) |
time time.tz |
string |
SUBSTRING(CONVERT(nvarchar(4000), EmployeeID, 126), 1 + CHARINDEX(N'T', CONVERT(nvarchar(4000), EmployeeID, 126)), 24) |
Les conversions de date et heure sont conçues pour fonctionner que la valeur soit stockée dans la base de données avec le type de données SQL Serverdatetime ou avec un type string. Notez que le type de données SQL Serverdatetime n'utilise pas timezone et offre une précision moins importante que le type de données XML time. Pour inclure le type de données timezone ou apporter une précision supplémentaire, stockez les données dans SQL Server avec un type string.
Lorsque vous convertissez un nœud du type de données XDR en type de données XPath, une conversion supplémentaire est parfois nécessaire (d'un type de données XPath vers un autre type de données XPath). Par exemple, imaginez la requête XPath suivante :
(@m + 3) = 4
Si @m est de type de données XDR fixed14.4, la conversion de ce type de données en type de données XPath s'effectue au moyen de l'élément de code suivant :
CONVERT(money, m)
Dans le cadre de cette conversion, le nœud m passe du type fixed14.4 au type money. Toutefois, l'ajout de la valeur 3 nécessite une autre conversion :
CONVERT(float(CONVERT(money, m))
L'expression XPath est évaluée comme suit :
CONVERT(float(CONVERT(money, m)) + CONVERT(float(53), 3) = CONVERT(float(53), 3)
Comme le montre le tableau ci-dessous, il s'agit de la même conversion que celle appliquée à d'autres expressions XPath (telles que des littéraux ou des expressions composées).
|
X est inconnu |
X est de type string |
X est de type number |
X est de type boolean |
string(X) |
CONVERT (nvarchar(4000), X, 126) |
- |
CONVERT (nvarchar(4000), X, 126) |
CASE WHEN X THEN N'true' ELSE N'false' END |
number(X) |
CONVERT (float(53), X) |
CONVERT (float(53), X) |
- |
CASE WHEN X THEN 1 ELSE 0 END |
boolean(X) |
- |
LEN(X) > 0 |
X != 0 |
- |
Exemples
A.Convertir un type de données dans une requête XPath
Dans la requête XPath suivante spécifiée par rapport à un schéma XSD annoté, la requête sélectionne tous les nœuds Employee avec la valeur d'attribut EmployeeID égale à E-1, où « E - » est le préfixe spécifié au moyen de l'annotation sql:id-prefix.
Employee[@EmployeeID="E-1"]
Le prédicat dans la requête équivaut à l'expression SQL suivante :
N'E-' + CONVERT(nvarchar(4000), Employees.EmployeeID, 126) = N'E-1'
EmployeeID étant l'une des valeurs de type de données id (idref, idrefs, nmtoken, nmtokens, et ainsi de suite) dans le schéma XSD, EmployeeID est converti en type de données XPath string à l'aide des règles de conversion décrites précédemment.
CONVERT(nvarchar(4000), Employees.EmployeeID, 126)
Le préfixe « E - » est ajouté à la chaîne et le résultat est ensuite comparé avec N'E-1'.
B.Effectuer plusieurs conversions de types de données dans une requête XPath.
Examinez la requête XPath suivante définie par rapport à un schéma XSD annoté : OrderDetail[@UnitPrice * @OrderQty > 98]
Cette requête XPath retourne tous les éléments <OrderDetail> qui répondent au prédicat @UnitPrice * @OrderQty > 98. Si l'élément UnitPrice est annoté avec un type de données fixed14.4 dans le schéma annoté, ce prédicat équivaut à l'expression SQL suivante :
CONVERT(float(53), CONVERT(money, OrderDetail.UnitPrice)) * CONVERT(float(53), OrderDetail.OrderQty) > CONVERT(float(53), 98)
Lors de la conversion des valeurs dans la requête XPath, la première conversion convertit le type de données XDR en type de données XPath. Le type de données XSD de l'élément UnitPrice étant fixed14.4, tel que décrit dans le tableau précédent, voici la première conversion employée :
CONVERT(money, OrderDetail.UnitPrice))
Du fait que les opérateurs arithmétiques convertissent leurs opérandes en type de données XPath number, la deuxième conversion (d'un type de données XPath à un autre) est appliquée là où la valeur est convertie en float(53) (float(53) est très proche du type de données XPath number) :
CONVERT(float(53), CONVERT(money, OrderDetail.UnitPrice))
Si l'on part du principe que l'attribut OrderQty ne dispose d'aucun type de données XSD, OrderQty est converti en type de données XPath number dans le cadre d'une conversion unique :
CONVERT(float(53), OrderDetail.OrderQty)
La valeur 98 est également convertie en type de données XPath number :
CONVERT(float(53), 98)
[!REMARQUE]
Si le type de données XSD appliqué au schéma est incompatible avec le type de données SQL Server sous-jacent dans la base de données, ou si une conversion de type de données XPath impossible est réalisée, SQL Server peut retourner une erreur. Par exemple, si l'attribut EmployeeID est annoté avec l'annotation id-prefix, le code XPath Employee[@EmployeeID=1] génère une erreur puisque EmployeeID possède l'annotation id-prefix et ne peut être converti en type number.