I. Généralités▲
Un prédicat commence par « [» et se termine par « ] ».
Un prédicat peut contenir des XPath et ainsi d'autres prédicats.
Un prédicat est une condition, on peut le comparer à la clause WHERE en SQL, il en diffère néanmoins par le fait qu'il ne porte pas sur l'intégralité du Xpath (sauf usage particulier de parenthèses), mais sur la combinaison axe+test qu'il suit directement : son contexte.
II. Opérateurs▲
II-A. Les opérateurs booléens▲
Les booléens sont true() et false(). Le nœud vide, la chaîne vide et zéro sont convertis en false().
- NON : c'est une fonction en XPath, not(…), elle englobe la partie sur laquelle porte la négation ;
- OU : or ;
- ET : and ;
- EGAL et DIFFERENT : = et != attention != n'est pas la négation de =, comme cela sera détaillé plus tard ;
- COMPARATEURS D'ORDRE : <=, <, >=, >.
II-B. Les opérateurs numériques▲
Si une de ces opérations est effectuée sur une chaîne de caractères la valeur renvoyée est NaN(Not a Number).
- ADDITION : + ;
- SOUSTRACTION : -, attention sur l'opérateur de soustraction, il faut toujours le faire précéder et suivre d'un espace sinon l'expression peut être confondue avec un nom d'élément ;
- MULTIPLICATION : * ;
- DIVISION: div ;
- MODULO: mod.
III. Test▲
Lors de test entraînant une comparaison tout nœud est converti en sa valeur textuelle. Celle-ci pourra être considérée comme un nombre (si sa forme le permet) ou une chaîne de caractères.
III-A. Test de valeur▲
Il porte sur la valeur textuelle du nœud sélectionné. On ne peut comparer que des types simples.
On notera ici l'importance du self::node() et de son raccourci «.».
Xpath : //AA[.=1]
<ROOT>
<AA>1</AA>
<AA>2</AA>
</ROOT>
Xpath : //AA[. > 1]
<ROOT>
<AA>1</AA>
<AA>2</AA>
</ROOT>
III-B. Test d'existence▲
On souhaite sélectionner un nœud en fonction de ses fils/père/attributs/etc. Dans ce cas, le XPath présent dans le prédicat sera évalué à partir du nœud sélectionné précédant ce même prédicat, il ne sera donc pas précédé de /.
Xpath : //AA[DD] (tous les AA possédant au moins un fils DD)
<ROOT>
<AA>
<BB>
<CC/>
</BB>
<DD/>
</AA>
<AA>
<BB/>
</AA>
</ROOT>
Xpath : //BB[*] (tous les BB possédant au moins un fils element)
<ROOT>
<AA>
<BB>
<CC/>
</BB>
<DD/>
</AA>
<AA>
<BB/>
</AA>
</ROOT>
Pour bien comprendre l'importance des chemins relatifs, le XPath suivant //AA[/*//AA/DD] se traduit par : tous les AA à condition qu'il existe un AA descendant de la racine possédant au moins un fils DD.
III-C. Test de position▲
On utilisera pour ceci une fonction XPath.
La fonction position() renvoie la position du nœud en lecture dans son contexte parent. La numérotation des positions en XPath commence à 1.
Xpath : /ROOT/AA[position()=2]
ou /ROOT/AA[2](écriture raccourcie) sélectionne le deuxième fils AA de ROOT
<ROOT>
<AA>
<BB>
<CC/>
</BB>
<DD/>
</AA>
<AA>
<BB/>
</AA>
</ROOT>
Quand on teste les positions, sauf si on utilise les parenthèses comme indiqué dans le chapitre 4, le contexte parent est le nœud parent.
Ainsi un XPath du type //*[2] ne renvoie pas le deuxième nœud de la sélection, mais tous les nœuds sélectionnés précédemment qui sont des deuxièmes fils.
Xpath : //*[2]
<ROOT>
<AA>
<BB>
<CC/>
</BB>
<DD/>
</AA>
<AA>
<BB/>
</AA>
</ROOT>
III-D. Différence entre = et !=▲
La différence entre = , != et leur négation se fait sensible lors de comparaison sur des ensembles.
Voyons déjà le comportement sur les ensembles.
Si on compare une valeur à un ensemble de nœuds via = , l'expression renvoie vrai si la valeur textuelle d'un des nœuds est égale à la valeur du test.
Xpath: //a[.=//b]
<r>
<a>1</a>
<a>5</a>
<b>1</b>
<b>2</b>
<b>3</b>
</r>
Si on compare une valeur à un ensemble de nœuds via != , l'expression renvoie vrai si la valeur textuelle d'un des nœuds est différente de la valeur du test.
Xpath: //a[.!=//b]
<r>
<a>1</a>
<a>5</a>
<b>1</b>
<b>2</b>
<b>3</b>
</r>
Si on inclut l'expression avec = dans une négation, l'expression renvoie vrai si toutes les valeurs textuelles sont différentes de la valeur du test.
Xpath: //a[not(.=//b)]
<r>
<a>1</a>
<a>5</a>
<b>1</b>
<b>2</b>
<b>3</b>
</r>
Si on inclut l'expression avec != dans une négation , l'expression renvoie vrai si toutes les valeurs textuelles sont égales à la valeur du test.
Xpath: //a[not(.!=//b)]
<r>
<a>1</a>
<a>5</a>
<b>1</b>
<b>2</b>
<b>3</b>
</r>
Xpath: //a[not(.!=//b)]
<r>
<a>1</a>
<a>5</a>
<b>1</b>
<b>1</b>
</r>
IV. Parenthèses et contexte▲
Les parenthèses sont utilisables non seulement à l'intérieur des prédicats, mais aussi sur les chemins Xpath.
À l'intérieur d'un prédicat, les parenthèses suivent les règles de priorité classiques des opérations logiques.
La syntaxe XPath nécessite que la parenthèse gauche soit toujours placée en tête du chemin, ainsi :
(/AA/DD) est bon, /AA(/DD) ou /AA/(DD) est faux.
La parenthèse va permettre de considérer tout le Xpath englobé comme un ensemble de nœuds sans contexte.
Ainsi pour les prédicats, en particulier sur ceux effectuant des tests de position, on ne tiendra plus compte du contexte du nœud.
Quelques exemples avec et sans parenthèses pour comparaison :
Xpath : /ROOT/AA/BB[position()=2]
<ROOT>
<AA>
<BB/>
</AA>
<AA>
<BB/>
<BB/>
</AA>
<AA>
<BB/>
</AA>
</ROOT>
Xpath :( /ROOT/AA/BB)[position()=2]
<ROOT>
<AA>
<BB/>
</AA>
<AA>
<BB/>
<BB/>
</AA>
<AA>
<BB/>
</AA>
</ROOT>
Xpath : /ROOT/AA/BB[position()=1]
<ROOT>
<AA>
<BB/>
</AA>
<AA>
<BB/>
<BB/>
</AA>
<AA>
<BB/>
</AA>
</ROOT>
Xpath :( /ROOT/AA/BB)[position()=1]
<ROOT>
<AA>
<BB/>
</AA>
<AA>
<BB/>
<BB/>
</AA>
<AA>
<BB/>
</AA>
</ROOT>
V. Quelques exemples combinés▲
Après avoir vu en détail les différents types d'opérateurs et de tests, la démonstration sera complète avec quelques exemples de combinaisons de ces notions.
V-A. Un nœud avec au moins N fils▲
Si on souhaite un nœud avec N fils, cela signifie qu'il possède au moins un fils de position N.
On le traduira par une syntaxe du type : Chemin_XPath[*[position()=N]].
Xpath : /ROOT/AA[*[position()=2]]
<ROOT>
<AA>
<BB/>
</AA>
<AA>
<BB/>
<BB/>
<BB/>
</AA>
<AA>
<BB/>
<BB/>
</AA>
</ROOT>
V-B. Enième élément par ordre d'apparition▲
Il n'est pas toujours évident de repérer le énième élément d'une structure arborescente. Pour ceci les parenthèses nous seront d'une grande aide.
Xpath : (//BB)[3]
<ROOT>
<BB>
<BB/>
</BB>
<AA>
<BB/>
<BB/>
</AA>
</ROOT>
V-C. Fils B d'un élément A si celui-ci possède aussi un fils C▲
Nous sommes simplement dans le cas où, au lieu d'être à la fin du XPath, le prédicat est au milieu.
Xpath : /ROOT/AA[CC]/BB
<ROOT>
<AA>
<BB/>
</AA>
<AA>
<BB/>
<CC/>
</AA>
</ROOT>
V-D. Fils C d'un élément B ou A▲
Il existe différentes façons de coder ceci, la méthode présentée ici a l'avantage de rester simple et d'être très peu coûteuse.
Xpath : /ROOT/*[self::AA or self::BB]/CC
<ROOT>
<BB>
<CC/>
</BB>
<EE>
<CC/>
</EE>
<AA>
<BB/>
<CC/>
</AA>
</ROOT>
V-E. Suppression de doublons▲
La technique est simple bien que gourmande en ressources. Pour éliminer les doublons, il suffit d'éliminer les éléments qui ont la particularité d'être précédés par un élément qui leur est identique.
Nous utiliserons pour ceci les axes preceding ou preceding-sibling.
Xpath: /r/*[not(preceding-sibling::*=.)]
<r>
<a>1</a>
<a>5</a>
<b>1</b>
<b>2</b>
<b>5</b>
</r>