Aux types déjà présents dans XPath 1.0 sont ajoutés les types de base définit pour XML Schema3 [1]. On y retrouve les types classiques en programmation mais aussi des types tels que xs:date ou xs:anyURI...
Une autre nouveauté est l’apparition du type «sequence» qui reprend la notion de «node-set». Voici quelques exemples :
Dans XPath 2.0, le résultat de toute expression, tout chemin est un séquence. Une étape de localisation a pour résultat une séquence de valeurs (éventuellement des noeuds) sur laquelle s’appliquera aussi bien un filtre qu’une autre étape de localisation (sur chacune des valeurs de la séquence). Ainsi, il est possible de faire : «(30 to 50)[. mod 5 = 0]» qui retourne la séquence «(30, 35, 40, 45, 50)». A noter qu’avec XPath 2.0, une valeur seule ou une séquence avec seulement la valeur est identique. Ainsi «2 = (2)».
De même, l’expression «/annuaire/personne[nom='Dupont']/prenom» se calculera de la manière suivante :
(/) /annuairedonne
(annuaire[1])
(/annuaire[1]) /personnedonne
(/annuaire[1]/personne[1], /annuaire[1]/personne[2])
(/annuaire[1]/personne[1], /annuaire[1]/personne[2]) [nom=‘Dupont’]donne
(/annuaire[1]/personne[2])
(/annuaire[1]/personne[2]) /prenomdonne
(/annuaire[1]/personne[2]/prenom[1])
De nouvelles fonctions sont associées aux séquences : distinct-values, remove, reverse, subsequence, avg, min, max, sum... L’ensembles des fonctions, parfois préfixées par «fn:», sont présentées dans le standard [2].
Avec XPath 2.0, il est aussi possible d’appuyer la recherche sur des documents complémentaires en utilisant «doc(URI)». Il existe aussi une nouvelle fonction nommée "idref", symétrique de la fonction "id" déjà présente en XPath 1.0. "idref", lorsque le paramètre est un identifiant XML, retourne une séquence d’attributs de type IDREF ou IDREFS qui contiennent cet identifiant.
Des opérateurs complexes apparaissent aussi. Ils s’appuient sur la notion de variable. Une variable en XPath s’écrit «$n» où «n» est son nom. Les nouveaux opérateurs sont les suivants :
Remarques :
some $name in exp1 satisfies exp2est équivalente à l’expression
exists( for $name in exp1 return if (exp2) then true() else () )
every $name in exp1 satisfies exp2est équivalente à l’expression
empty( for $name in exp1 return if (exp2) then () else false() )
Dans cette nouvelle version de XPath, il faut être attentif au fonctionnement des opérateurs de comparaison. L’utilisation de ceux-ci dépend des valeurs produites par les opérandes.
Tout d’abord, si les opérandes retournent une seule valeur (ou un séquence à une valeur), elles sont appelées «atomiques». Les opérateurs adaptés sont alors :
Ainsi, les expressions suivantes sont valides :
8 eq 4+4
(//date)[1]/@format eq ‘ISO’
Si un des deux opérandes est une séquence d’au moins deux valeurs, la comparaison avec les opérateurs ci-dessus sera systématiquement fausse. En revanche, ce type d’opérande sera valide pour les opérateurs «=», «!=», «<», «>», etc. Mais attention à leur fonctionnement ! En effet, ils sont «vrai» si au moins un couple de valeurs prises dans chacun des opérandes vérifie la comparaison.
Ainsi, les expressions suivantes sont valides [3] :
8 = 4+4car c’est aussi
(8) = (4+4)
(1, 2) = (2, 4)car il y a un 2 dans chacune des séquences ;
//personne/nom/text() = ‘Albert’
Il existe aussi des comparateurs sur les noeuds de l’arbre XML. «is» détermine si deux résultats référencent le même noeud. Ainsi, l’expression suivante est vérifiée :
(//personne)[2] is //personne[nom eq ‘Dupont’]
Dans le même esprit, XPath 2.0 propose deux opérateurs d’ordre «<<« et «>>». Ainsi, l’expression suivante est vérifiée :
(//personne)[4] >> (//personne)[3]
L’utilisation des opérateurs de comparaison n’est pas très naturelle. Il convient donc d’y être attentif et d’utiliser les opérateurs adaptés. Par exemple :
((//personne)[1]/prenom,(//personne)[1]/date) eq ((//personne)[2]/prenom[2], (//personne)[2]/date))n’est vérifiée, car les arguments ne sont pas des singletons ;
((//personne)[1]/prenom, (//personne)[1]/date) = ((//personne)[2]/prenom[2], (//personne)[2]/date))est vérifiée, car les deux prénoms sont les mêmes ;
((//personne)[1]/prenom, (//personne)[1]/date) is ((//personne)[2]/prenom[2], (//personne)[2]/date))provoque une «runtime error», car les arguments ne sont pas des singletons.
Les opérateurs logiques sont habituels «and» et «or». Attention au changement de type implicite. Les arguments valent «false» si la valeur est :
Les valeurs constantes sont obtenues par les fonctions «true()» et «false()». Attention, la négation n’est pas un opérateur, mais une fonction «not(...)» !
La plupart des outils de manipulation XML ont des fonctions comprenant XPath 1.0. En revanche, il y a actuellement encore peu d’outils qui gèrent XPath 2.0.
Point | 2.0 | 1.0 |
---|---|---|
Implémentations courante | - | ++ |
Librairie de fonctions | +++ | + |
Transtypage implicite | + | +++ |
“4” < “4.0” | «true» | «false» |
Des outils pour s'essayer à XPath : oXygen, XPontus, BaseX
Reprendre l'exercice 1 de la section "Xpath", en refaisant les requêtes avec XPath 2.0 (ne refaire que celle qui sont modifiées).
Reprendre l'exemple de l'exercice précédent ("jailu.xml").
«Calculer» le résultat des expressions XPath suivantes (indiquer si elles sont ou pas valables en XPath 1.0 et en XPath 2.0) :
distinct-values(/edition/auteur/@pays)
doc("jailu.xml")/edition/auteur
id( /edition/livre[ every $n in /edition/livre/@annee satisfies $n le @annee ]/ref-auteur/@ref )/@nom
id( /edition/livre[ number(@annee) ge max(/edition/livre/@annee) ]/ref-auteur/@ref )/@nom
Soit la DTD "edition.dtd" décrivant une classe de documents dont "edt1213.xml" est un exemple.
Donner le résultat de la requête XPath suivante sur le document. Expliquez ce qu’elle recherche.
/edt/liste_profs/prof[ @idprof = /edt/liste_semaines/semaine/jour/creneau/@nprof ]/concat(prenom,' ',nom)
Parmi les requêtes suivantes, indiquez, en justifiant votre choix, lesquelles donnent le même résultat que la requête de la question précédente ? En cas de réponse négative, donnez les raisons.
/edt/liste_semaines/semaine/jour/creneau/@nprof/concat(prenom,' ',nom)
id(/edt/liste_semaines/semaine/jour/creneau/@nprof)/concat(prenom,' ',nom)
/edt/liste_profs/prof[ @idprof = ../../liste_semaines/semaine/jour/creneau/@nprof ]/concat(prenom,' ',nom)
/edt/liste_profs/prof[ @idprof = ../../../liste_semaines/semaine/jour/creneau/@nprof ]/concat(prenom,' ',nom)
concat(id(/edt/liste_semaines/semaine/jour/creneau/@nprof)/prenom,' ', id(/edt/liste_semaines/semaine/jour/creneau/@nprof)/nom)
/edt/liste_profs/prof[ some $c in /edt/liste_semaines/semaine/jour/creneau satisfies $c/@nprof eq @idprof ]/concat(prenom,' ',nom)
/edt/liste_profs/prof[ every $c in /edt/liste_semaines/semaine/jour/creneau satisfies $c/@nprof eq @idprof ]/concat(prenom,' ',nom)
/edt/liste_profs/prof[id(@idprof)]/concat(prenom,' ',nom)
/edt/liste_profs/prof[exists(idref(@idprof))]/concat(prenom,' ',nom)
Soit la DTD et l'exemple de l'exercice précédent.
Écrire les requêtes XPath (sans utiliser "//") permettant d'obtenir les informations suivantes :
lu 19/03/2007 me 21/03/2007 je 22/03/2007 ve 23/03/2007
/edt[1]/types_creneaux[1]/plage[4]/hdeb[1] - 14:00:00 /edt[1]/types_creneaux[1]/plage[5]/hdeb[1] - 15:30:00 /edt[1]/types_creneaux[1]/plage[6]/hdeb[1] - 17:00:00
28/03
27/03
3.25
2.6
Jean-Pierre Fabriol : 0252125487
Pour chaque requête, les résultats présentés sont ceux obtenus avec oXygen 8.1 et XPath 2.0. Les chemins ne font pas partie de la réponse, oXygen les places pour localiser la réponse. Seule l'information après le '-' est valable.
Notes
1. http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/datatypes.html#built-in-datatypes.
2. http://www.w3.org/2005/04/xpath-functions/.
3. XPath ne respecte pas les propriétés «intuitives» et mathématiques des opérateurs de comparaison habituels :