XPath - Localiser les données
Le chapitre précédent, peu technique, a surtout été l’occasion de faire connaissance avec le vocabulaire utilisé dans XPath. Je préfère vous prévenir, ce nouveau chapitre sera dense !
Nous allons aborder toutes les notions qui vous permettront d’utiliser XPath afin d’exploiter facilement vos documents XML. Au programme donc : la dissection détaillée d’une étape et un peu de pratique via EditiX.
Dissection d’une étape
Dans le chapitre précédent, nous avons vu qu’une expression XPath est en réalité une succession d’étapes. Nous allons maintenant nous intéresser de plus près à ce qu’est une étape.
Une étape est décrite par 3 éléments :
- Un axe.
- Un nœud ou un type de nœud.
- Un ou plusieurs prédicats (facultatif).
Avant de voir en détail les valeurs possibles pour ces 3 éléments, je vous propose de revenir très rapidement sur leurs rôles respectifs.
L’axe
L’axe va nous permettre de définir le sens de la recherche. Par exemple, si l’on souhaite se diriger vers un nœud enfant ou au contraire remonter vers un nœud parent voir un ancêtre.
Le nœud
Ce second élément va nous permettre d’affiner notre recherche en indiquant explicitement le nom d’un nœud ou le type de nœud dont les informations nous intéressent.
Les prédicats
Comme précisé un peu plus haut, ce dernier élément est facultatif. Les prédicats, dont le nombre n’est pas limité, agissent comme un filtre et vont nous permettre de gagner en précision lors de nos recherches. Ainsi, grâce aux prédicats, il sera par exemple possible de sélectionner les informations à une position précise.
Maintenant que nous savons comment former une étape, il nous reste à apprendre la syntaxe nous permettant de les ordonner et ainsi de pouvoir écrire une étape compatible avec XPath :
axe::nœud[predicat][predicat]...[predicat]
Les axes
Comme nous l’avons vu dans la partie précédente, un axe est le premier élément formant une étape. Son rôle est de définir le sens de la recherche. Bien évidemment, le choix du sens est structuré par un vocabulaire précis que nous allons étudier maintenant.
Le tableau récapitulatif
Nom de l'axe | Description |
---|---|
ancestor | oriente la recherche vers les ancêtres du nœud courant |
ancestor-or-self | oriente la recherche vers le nœud courant et ses ancêtres |
attribute | oriente la recherche vers les attributs du nœud courant |
child | oriente la recherche vers les enfants du nœud courant |
descendant | oriente la recherche vers les descendants du nœud courant |
descendant-or-self | oriente la recherche vers le nœud courant et ses descendants |
following | oriente la recherche vers les nœuds suivant le nœud courant |
following-sibling | oriente la recherche vers les frères suivants du nœud courant |
parent | oriente la recherche vers le père du nœud courant |
preceding | oriente la recherche vers les nœuds précédant le nœud courant |
preceding-sibling | oriente la recherche vers les frères précédents du nœud courant |
self | oriente la recherche vers le nœud courant |
namespace
qui permet d’orienter la recherche vers un espace de noms. Je l’ai volontairement retiré du tableau récapitulatif car nous ne l’utiliserons pas dans le cadre de ce tutoriel. Quelques abréviations
Tout au long de notre découverte des axes, des tests de nœuds et des prédicats, nous allons découvrir qu’il est possible d’utiliser des abréviations afin de rendre la syntaxe de nos expressions XPath plus claire et concise.
L’axe child
Pour les axes, il existe une abréviation possible et elle concerne l’axe child
. En réalité, lorsque l’on souhaite orienter la recherche vers l’axe child
, ce n’est pas nécessaire de le préciser. Il s’agit de l’axe par défaut.
Les tests de nœuds
Nous venons donc de voir les différentes valeurs possibles pour sélectionner un axe. Il est donc maintenant temps d’attaquer le second élément composant une étape : le nom d’un nœud ou le type de nœud.
Nom | Description |
---|---|
nom du nœud | oriente la recherche vers le nœud dont le nom a explicitement été spécifié |
* | oriente la recherche vers tous les nœuds |
node() | oriente la recherche vers tous les types de nœuds (éléments, commentaires, attributs, etc.) |
text() | oriente la recherche vers les nœuds de type texte |
comment() | oriente la recherche vers les nœuds de type commentaire |
processing-instruction()
. Je l’ai volontairement retiré du tableau récapitulatif car nous ne l’utiliserons pas dans le cadre de ce tutoriel. Quelques exemples
Puisque les prédicats sont facultatifs dans les expressions XPath, je vous propose de voir d’ores et déjà quelques exemples. Pour les exemples, nous allons nous appuyer sur le document XML que nous avons déjà utilisé :
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<repertoire>
<!-- John DOE -->
<personne sexe="masculin">
<nom>DOE</nom>
<prenom>John</prenom>
<adresse>
<numero>7</numero>
<voie type="impasse">impasse du chemin</voie>
<codePostal>75015</codePostal>
<ville>PARIS</ville>
<pays>FRANCE</pays>
</adresse>
<telephones>
<telephone type="fixe">01 02 03 04 05</telephone>
<telephone type="portable">06 07 08 09 10</telephone>
</telephones>
<emails>
<email type="personnel">john.doe@wanadoo.fr</email>
<email type="professionnel">john.doe@societe.com</email>
</emails>
</personne>
</repertoire>
Les chemins absolus
Nous allons débuter par des exemples se basant sur l’écriture d’une expression utilisant un chemin absolu.
Dans notre premier exemple, le but va être de récupérer le pays de domiciliation de John DOE. Commençons par décrire les étapes à suivre en français :
- Étape 1 : descendre au nœud
repertoire
. - Étape 2 : descendre au nœud
personne
. - Étape 3 : descendre au nœud
adresse
. - Étape 4 : descendre au nœud
pays
.
Traduisons maintenant ces étapes sous la forme d’expressions XPath :
- Étape 1 :
child::repertoire
. - Étape 2 :
child::personne
. - Étape 3 :
child::adresse
. - Étape 4 :
child::pays
.
Ce qui nous donne :
/child::repertoire/child::personne/child::adresse/child::pays
Il est possible de simplifier l’écriture de cette expression. En effet, comme je l’ai dit dans le chapitre sur les axes, l’axe child
est celui par défaut, il n’est donc pas nécessaire de le préciser. Ainsi, il est possible de simplifier notre expression de la sorte :
/repertoire/personne/adresse/pays
Maintenant que vous êtes un peu plus à l’aise avec la syntaxe de XPath, je vous propose de voir un exemple un peu plus exotique. Le but est de trouver maintenant l’expression XPath permettant de trouver tous les commentaires de notre document XML.
Dans ce nouvel exemple, une seule étape est en réalité nécessaire et consiste à sélectionner tous les descendants du nœud racine qui sont des commentaires.
Tentons maintenant de traduire cette étape sous la forme d’expressions XPath :
- On sélectionne tous les descendants avec l’expression
descendant
. - On filtre les commentaires avec l’expression
comment()
.
Ce qui nous donne :
/descendant::comment()
Les chemins relatifs
Après avoir vu quelques exemples d’expressions XPath utilisant des chemins absolus, je vous propose de voir un exemple d’une expression utilisant un chemin relatif. Dans cet exemple, notre point de départ sera le nœud telephones
. Une fois de plus, le but va être de récupérer le pays de domiciliation de John DOE. Commençons par décrire les étapes à suivre en français :
- Étape 1 : remonter au nœud frère
adresse
. - Étape 2 : descendre au nœud
pays
.
Traduisons maintenant ces étapes sous la forme d’expressions XPath :
- Étape 1 :
preceding-sibling::adresse
. - Étape 2 :
pays
.
Ce qui nous donne :
preceding-sibling::adresse/pays
Quelques abréviations
Tout comme pour les axes, il existe quelques abréviations dont je vous conseille d’abuser afin de rendre vos expressions XPath plus lisibles et légères.
L’expression /descendant-or-self::node()/
Dans nos expressions XPath, il est possible de remplacer l’expression /descendant-or-self::node()/
par //
.
Ainsi, l’expression :
/descendant-or-self::node()/pays
peut être simplifiée par :
//pays
L’expression self::node()
Notre deuxième abréviation va nous permettre de remplacer l’expression /self::node()/
par .
.
Ainsi, l’expression :
/repertoire/personne/self::node()
peut être simplifiée par :
/repertoire/personne/.
L’expression parent::node()
Notre dernière abréviation va nous permettre de remplacer l’expression /parent::node()/
par ..
.
Les prédicats
Nous venons donc de voir deux des trois éléments formant une étape dans une expression XPath. Dans ce chapitre, nous allons donc aborder l’élément manquant : les prédicats.
Le tableau récapitulatif
Nom du prédicat | Description |
---|---|
attribute | permet d'affiner la recherche en fonction d'un attribut |
count() | permet de compter le nombre de nœuds |
last() | permet de sélectionner le dernier nœud d'une liste |
position() | permet d'affiner la recherche en fonction de la position d'un nœud |
name()
, id()
ou encore string-length()
. Je les ai volontairement retirées du tableau récapitulatif car nous ne l’utiliserons pas dans le cadre de ce tutoriel. Quelques exemples
Pour les exemples, nous allons continuer de nous appuyer sur le même document XML :
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<repertoire>
<!-- John DOE -->
<personne sexe="masculin">
<nom>DOE</nom>
<prenom>John</prenom>
<adresse>
<numero>7</numero>
<voie type="impasse">impasse du chemin</voie>
<codePostal>75015</codePostal>
<ville>PARIS</ville>
<pays>FRANCE</pays>
</adresse>
<telephones>
<telephone type="fixe">01 02 03 04 05</telephone>
<telephone type="portable">06 07 08 09 10</telephone>
</telephones>
<emails>
<email type="personnel">john.doe@wanadoo.fr</email>
<email type="professionnel">john.doe@societe.com</email>
</emails>
</personne>
</repertoire>
Premier exemple
Dans notre premier exemple, le but va être de récupérer le nœud contenant le numéro de téléphone fixe de John DOE. Bien évidemment, il existe plusieurs façons d’y arriver. Je vous propose d’utiliser celle qui pousse le moins à réfléchir : nous allons sélectionner tous les descendants du nœud racine et filtrer sur la valeur de l’attribut type
. Ce qui nous donne :
/descendant::*[attribute::type="fixe"]
Bien évidemment, cette méthode est à proscrire car elle peut avoir de nombreux effets de bord. Il est possible de procéder autrement en précisant le chemin complet :
/repertoire/personne/telephones/telephone[attribute::type="fixe"]
Terminons ce premier exemple en sélectionnant les numéros de téléphones qui ne sont pas des numéros de téléphones fixes. Une fois de plus, il existe plusieurs façons de procéder. La première, qui a priori est la plus simple, consiste à remplacer dans notre expression précédente l’opérateur d’égalité =
par l’opérateur de non égalité !=
:
/repertoire/personne/telephones/telephone[attribute::type!="fixe"]
Une autre méthode consiste à utiliser la fonction not()
:
/repertoire/personne/telephones/telephone[not(attribute::type="fixe")]
A noter : la double négation nous fait revenir à notre point de départ. En effet, les 2 expressions suivantes sont équivalentes :
/repertoire/personne/telephones/telephone[not(attribute::type!="fixe")]
/repertoire/personne/telephones/telephone[attribute::type="fixe"]
Deuxième exemple
Après avoir manipulé les attributs, je vous propose maintenant de manipuler les positions. Ainsi, notre deuxième exemple consiste à sélectionner le premier numéro de téléphone de John DOE. Commençons par détailler les étapes en français :
- Étape 1 : descendre au nœud
repertoire
. - Étape 2 : descendre au nœud
personne
. - Étape 3 : descendre au nœud
telephones
. - Étape 4 : sélectionner le premier nœud
telephone
.
Traduisons maintenant ces étapes sous la forme d’expressions XPath :
- Étape 1 :
repertoire
. - Étape 2 :
personne
. - Étape 3 :
telephones
. - Étape 4 :
telephone[position()=1]
.
Ce qui nous donne :
/repertoire/personne/telephones/telephone[position()=1]
Si l’on souhaite maintenant sélectionner le dernier nœud téléphone
de la liste, on modifiera l’expression de la manière suivante :
/repertoire/personne/telephones/telephone[last()]
Quelques abréviations
Comme pour les axes, nous n’allons voir ici qu’une seule abréviation et elle concerne le prédicat attribute
qu’il est possible de remplacer par le symbole @
. Ainsi, l’expression :
/repertoire/personne/telephones/telephone[attribute::type="fixe"]
devient :
/repertoire/personne/telephones/telephone[@type="fixe"]
Un exemple avec EditiX
Pour conclure ce chapitre, je vous propose de voir comment exécuter une expression XPath avec EditiX.
Le document XML
Commencez par créer dans EditiX un document XML contenant les informations suivantes :
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<repertoire>
<!-- John DOE -->
<personne sexe="masculin">
<nom>DOE</nom>
<prenom>John</prenom>
<adresse>
<numero>7</numero>
<voie type="impasse">impasse du chemin</voie>
<codePostal>75015</codePostal>
<ville>PARIS</ville>
<pays>FRANCE</pays>
</adresse>
<telephones>
<telephone type="fixe">01 02 03 04 05</telephone>
<telephone type="portable">06 07 08 09 10</telephone>
</telephones>
<emails>
<email type="personnel">john.doe@wanadoo.fr</email>
<email type="professionnel">john.doe@societe.com</email>
</emails>
</personne>
<!-- Marie POPPINS -->
<personne sexe="feminin">
<nom>POPPINS</nom>
<prenom>Marie</prenom>
<adresse>
<numero>28</numero>
<voie type="avenue">avenue de la république</voie>
<codePostal>13005</codePostal>
<ville>MARSEILLE</ville>
<pays>FRANCE</pays>
</adresse>
<telephones>
<telephone type="bureau">04 05 06 07 08</telephone>
</telephones>
<emails>
<email type="professionnel">contact@poppins.fr</email>
</emails>
</personne>
</repertoire>
La vue XPath
Afin de pouvoir exécuter des expressions XPath, nous allons devoir afficher la vue dédiée au sein de EditiX. Pour ce faire, vous pouvez sélectionner dans la barre de menu XML puis XPath view ou encore utiliser le raccourci clavier Ctrl
+ Shift
+ 4
.
La fenêtre suivante doit alors apparaître :
Comme vous pouvez le constater, cette vue se compose de plusieurs éléments :
- Un champ dans lequel toutes nos expressions seront écrites.
- 2 boutons permettant de choisir si notre expression utilise un chemin relatif ou absolu.
- Une puce permettant de choisir la version de XPath à utiliser (prenez l’habitude de travailler avec la version 2).
- Des onglets permettant notamment d’afficher les informations sélectionnées par nos expressions.
Exécuter une requête
Dans cet ultime exemple, nous allons sélectionner les nœuds contenant des adresses e-mails professionnelles grâce à l’expression suivante :
/repertoire/personne/emails/email[attribute::type="professionnel"]
En théorie, nous devrions avoir 2nœuds sélectionnés. Vérifions tout de suite :
Le résultat est bien celui souhaité ! 😉
En résumé
- Une étape est composée d’un axe, d’un nœud ou type de nœud et d’un ou plusieurs prédicats.
- L’axe par défaut est l’axe
child
. - De nombreuses abréviations permettent de simplifier l’écriture des expressions XPath.
Ce cours vous plait ?
Retrouvez ce cours en livre physique sur Amazon !