XPath 1.0 : Types, axes et éléments

Erwan Amoureux

Les bases du langage XPath 1.0 : types et méthodes de parcours des arbres XML.
Les prédicats sont traités dans l'article XPath : fonctionnement des prédicats.
Un remerciement spécial pour avoir épluché mon orthographe et ma ponctuation à ClaudeLELOUP.

Commentez

- Titre : XPath 1.0 : Types, axes et éléments

- Auteur : Erwan Amoureux

- Parution : 5 décembre 2010

- Mise à jour : 13 juillet 2020

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2010 Erwan Amoureux. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Notions générales

- I-A. Objet

- I-B. Composition

- II. Types principaux

- II-A. Mécanisme du typage en Xpath

- II-B. Types de nœud

- II-B-1. Vocabulaire

- II-B-2. Text (texte)

- II-B-3. Element (élément)

- II-B-4. Attribute (attribut)

- II-B-5. Root (racine)

- II-B-6. Namespace (espace de nom)

- II-B-7. Comment (commentaire)

- II-B-8. Processing-instruction (instruction processeur)

- II-C. Types simples

- III. Test d'un nœud

- IV. Axes

- IV-A. Père/fils

- IV-B. Soi-même

- IV-C. Ancêtre/descendant

- IV-D. Précédent/suivant

- IV-E. Frères

- IV-F. Les attributs

- V. L'union

- VI. Le nodeset (collection de nœuds)

I - Notions générales

I-A - Objet

XPath 1.0 est un langage avec une syntaxe non XML, permettant d'adresser les différents nœuds ou groupes de nœuds particuliers d'un document XML. Les expressions XPath permettent également de représenter des chaînes de caractères, des nombres et des booléens.

Néanmoins, il n'est qu'un langage de sélection, pas un langage de requête, contrairement à SQL pour les BDD.

En effet, il ne permet pas de transformer le résultat final ni d'y ajouter des éléments extérieurs, tâche dédiée à des outils comme XSLT ou Xquery.

I-B - Composition

Une expression Xpath est composée de segments séparés par « / ».

Chaque segment est évalué par rapport au précédent.

Deux cas peuvent être rencontrés sur le premier segment :

- le premier segment commence par «/» : ce qui suit est évalué par rapport à la racine (différente de l'élément racine) ;

- le premier segment commence directement par une expression. Dans cette situation, fréquente dans les prédicats par exemple, le Xpath sera évalué par rapport au nœud qui est en lecture à ce moment.

Soit le XPath /A/B.
Ce XPath est composé de trois segments qui vont s'évaluer de façon séquentielle de gauche à droite :

- / : le premier élément, qui indique qu'on se positionne au début du document ;

- A : on évalue par rapport au début du document (segment précédent), tous les éléments du document qui correspondent à A ;

- B : à partir de chaque élément sélectionné dans A (parcourus de haut en bas, suivant l'ordre du document) on sélectionne les éléments satisfaisant à B.

Un segment est composé de deux parties obligatoires : un axe et un test, et d'une optionnelle : le prédicat.

Attention néanmoins il existe certains raccourcis d'écriture qui permettent d'omettre la déclaration de l'axe ou du test.

- Un axe : permet de se déplacer dans l'arbre des nœuds XML: parents, fils, ancêtres…
Par exemple :Child, parent, ancestor, self…

- Un test : permet d'identifier le type du nœud recherché ou son nom : attribut, racine… Il suit l'axe et doit être précédé de :: .
Par exemple : parent::*, child::comment(), child::A …

- Un prédicat : il consiste en conditions sur les nœuds parcourus. Il est encadré par [ ] .

II - Types principaux

II-A - Mécanisme du typage en Xpath

On peut différencier deux grandes familles dans le typage XPath :

- les types de nœuds : qui permettent de représenter et parcourir les différentes composantes d'un arbre XML ;

- les types simples : nombre, chaîne de caractères, etc. utilisés lors de test ou comme représentation de résultat.

II-B - Types de nœud

II-B-1 - Vocabulaire

- nœud parent : le ou les types de nœuds qui peuvent contenir celui-ci.

- nœud fils : le ou les types de nœuds qu'on peut retrouver dans ce nœud.

- expression xpath : les expressions xpath permettant de cibler ce type de nœud : test et/ou axe.

- valeur textuelle : la valeur utilisée lors d'un affichage ou d'une comparaison.

II-B-2 - Text (texte)

- nœud parent : element

- nœud fils : aucun

- expression xpath : node() (test), text()(test)

- valeur textuelle : la chaîne de caractères contenue

Les nœuds de type text sont les chaînes de caractères contenues entre les balises d'un XML.

Elles sont elles aussi vues comme des nœuds.

<?xml version="1.0"?>
<racine>
<AAA>
<BBB>b</BBB>
</AAA>
<AAA>a</AAA>
</racine>

Ici b et a >sont des nœuds text. Attention une même balise peut avoir plusieurs nœuds text dans le cas de contenu mixte, exemple :

<?xml version="1.0"?>
<racine>
<AAA>a<BBB/>b<CCC/>c</AAA>
</racine>

Ici par exemple le nœud AAA contient trois nœuds texta, b et c.

II-B-3 - Element (élément)

- nœud parent : root, element

- nœud fils : attribute, namespace, element, comment, text

- expression xpath : node()(test), * (test) (par défaut sauf derrière namespace et attribute)

- valeur textuelle : ensemble des contenus nœuds text qui sont ses descendants

Les nœuds de type element sont les plus évidents, ce sont les balises qui permettent de structurer l'information.

<?xml version="1.0"?>
<racine>
<AAA>
<BBB>b</BBB>
</AAA>
<AAA>a</AAA>
</racine>

Dans cet exemple nous avons : racine, AAA (2 éléments), BBB . AAA, BBB, racine sont les noms de ces éléments ; seuls les nœuds de type element possèdent des noms. Le nœud racine est le root element (élément racine).

La valeur textuelle de BBB est b.

La valeur textuelle de AAA contenant BBB est b.

La valeur textuelle de l'autre AAA est a.

La valeur textuelle de racine est ba.

II-B-4 - Attribute (attribut)

- nœud parent : element

- nœud fils : aucun

- expression xpath : @*,attribute::* (axe+test). La norme devrait permettre node() seul mais des limites de parseur l'empêchent en général. On peut néanmoins utiliser node() pour un attribut dans l'axe self::node() qui sera vu à la suite.
C'est donc * précède de l'axe qui fixe le type recherché.

- valeur textuelle : chaîne de caractères entre les quotes après le =

<?xml version="1.0"?>
<racine>
<AAA num="1"/>
</racine>

ici la valeur textuelle du nœud attributenum du nœud elementAAA est 1.

Ne pas oublier qu'une seule occurrence de « nom » d'attribut par nœud est autorisée. Attention aussi à l'emploi des " et ' .

II-B-5 - Root (racine)

- nœud parent : aucun

- nœud fils :element,comment,processing-instruction

- expression xpath : node() (test), / (axe)

- valeur textuelle : ensemble des contenus nœuds textes qui sont ses descendants.

Pour un XML du type

<?xml version="1.0"?>
<racine>
<AAA>
<BBB>b</BBB>
<CCC>c</CCC>
</AAA>
<AAA>a</AAA>
</racine>

sa valeur textuelle est : bca.

Le nœud racine (root) est l'élément hiérarchique le plus haut du document, c'est le nœud « invisible » qui contient tous les autres. Il faut le différencier du root element (élément racine) qui est l'unique nœud (et donc le premier) de type element qu'il peut avoir comme fils.

II-B-6 - Namespace (espace de nom)

- nœud parent : element

- nœud fils : aucun

- expression xpath : namespace::* (axe+test).Comme pour l'attribut, la norme devrait permettre node() seul mais cela ne se retrouve que pour l'axe self::node().C'est donc seulement * précédé de l'axe qui sera utilisé.

- valeur textuelle : l'URI de l'espace de noms qui est associée au préfixe de l'espace de noms

Les namespaces permettent d'associer certains nœuds via leur nom expansé à leur URI à un traitement particulier. Prenons par exemple une feuille XSLT :

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<test>
<xsl:value-of select="."/>
</test>
</xsl:template>
</xsl:stylesheet>

le nœud namespace est xmlns:xsl, sa valeur textuelle :http://www.w3.org/1999/XSL/Transform Tous les nœuds commençant par xsl: (le nom expansé) comme indiqué par xmlns:xsl seront associés à l'URI et, dans ce cas, si lus par un processeur XSLT, seront considérés comme des instructions au lieu d'être du simple texte.

II-B-7 - Comment (commentaire)

- nœud parent : element, root

- nœud fils : aucun

- expression xpath : node() (test), comment() (test)

- valeur textuelle : La chaîne entre <!-- et -->

Même syntaxe que pour le HTML, le commentaire est là pour « expliquer ». Néanmoins Xpath permet de le cibler et donc d'utiliser son contenu.

<?xml version="1.0"?>
<!--commentaires 1-->
<racine>
<AAA >
</racine>

Ce commentaire a pour valeur textuelle commentaires 1.

II-B-8 - Processing-instruction (instruction processeur)

- nœud parent : root

- nœud fils : aucun

- expression xpath : node()(test), processing-instruction() (test)

- valeur textuelle : ce qui est contenu entre <? et ?>

Ces nœuds sont des instructions de traitement au processeur, exemple :

<?xml-stylesheet type=« text/xsl » href=« xml-xpath.xslt »?>

Qui ordonne d'associer le xslt contenu mon fichier.xslt avec le XML traité. Ici par exemple la valeur textuelle est : xml-stylesheet type=« text/xsl » href=« xml-xpath.xslt ».
ATTENTION

<?XML version=« 1.0 » encoding=« UTF-8 »?>

L'en-tête du fichier ne peut jamais être atteint par Xpath , il est hors du nœud root. Il est donc impossible de récupérer l'encoding du document via Xpath.

II-C - Types simples

Dans sa version 1.0, XPath ne manipule que trois types simples :

- number : les nombres, toute chaîne chiffrée utilisant un point comme séparateur ;

- string : toute chaîne de caractères, on les représentera entre guillemets dans un XPath ;

- boolean : true() et false(). Pour les conversions le nombre 0 ainsi que la chaîne vide valent false().

Attention les types ne sont pas prédéfinis et une même valeur peut varier de type en fonction de l'utilisation. C'est bien entendu particulièrement vrai pour les nombres. Malheureusement, il n'existe pas de type date avant XPath 2.0.

III - Test d'un nœud

Deux tests sont possibles sur un nœud XML :

- tester son type ;

- tester son type et son nom.

Comme seuls les éléments et les attributs possèdent un nom, il n'y a que ces derniers à être concernés par cette possibilité.

IV - Axes

La meilleure façon de se représenter un arbre XML est de le voir comme un arbre généalogique avec ses pères, ses fils, ses descendants, ses ancêtres… C'est d'ailleurs le choix du Xpath qui puise allégrement dans le vocabulaire familial pour ses axes de recherches.

Rappel : tous les XPath suivants seront évalués à partir de la racine du document, ils commenceront donc par « / ».

IV-A - Père/fils

L'axe le plus utilisé est celui du fils child:: suivi d'un test. Il est d'ailleurs tellement fréquent que le raccourci d'écriture consiste à l'omettre ainsi

/child::* (qui récupère le premier élément après la racine soit le root element)

s'écrira

/*

Enfin la structure de base du XML étant l'élément et ce dernier se définissant par son nom, le test le plus courant porte sur lui.

Ainsi

/child::DEBUT (qui récupère le premier élément après la racine si ce dernier s'appelle DEBUT)

s'écrira

/DEBUT

Nous allons étudier quelques exemples de XPath portant sur des fils.

Pour la suite les éléments sélectionnés apparaîtront en rouge

XPath : /ROOT/AA

<ROOT>

<AA>

<BB/>

</AA>

<AA>

<BB/>

<CC/>

</AA>

</ROOT>

XPath : /ROOT/AA/CC

<ROOT>

<AA>

<BB/>

</AA>

<AA>

<BB/>

<CC/>

</AA>

</ROOT>

L'axe parent s'écrit parent::. Dans la hiérarchie XML comme ne peuvent être parent que root (la racine) et des nœuds element, il existe un raccourci d'écriture pour parent::*, c'est ..

XPath : /ROOT/*/BB/..

<ROOT>

<AA>

<BB/>

</AA>

<EE>

<BB/>

<CC/>

</EE>

</ROOT>

XPath : /ROOT/*/BB/parent::EE

<ROOT>

<AA>

<BB/>

</AA>

<EE>

<BB/>

<CC/>

</EE>

</ROOT>

IV-B - Soi-même

Se sélectionner soi-même peut sembler bizarre, mais c'est en réalité une expression très utilisée quand on pose des conditions ou avec l'axe des descendants.

Se sélectionner soi-même s'écrit self::node(), mais on lui préfère le raccourci « . »

XPath : /ROOT/AA/.

<ROOT>

<AA>

<BB/>

</AA>

<EE>

<BB/>

<CC/>

</EE>

<ROOT>

IV-C - Ancêtre/descendant

À un degré plus large que le fils ou le père, nous avons les descendants et les ancêtres.

L'axe descendant sélectionne tous les nœuds spécifiés contenus dans le nœud original.

Il s'écrit descendant::

XPath : /ROOT/descendant::*

<ROOT>

<AA>

<BB>

<CC/>

</BB>

<DD/>

</AA>

<AA>

<BB/>

</AA>

</ROOT>

XPath : /ROOT/descendant::CC

<ROOT>

<AA>

<BB>

<CC/>

</BB>

<DD/>

</AA>

<AA>

<BB/>

</AA>

</ROOT>

Il existe une variante permettant de sélectionner en plus le nœud à l'origine descendant-or-self:: , le raccourci pour cela est //

XPath : /ROOT/descendant-or-self::* ou /ROOT//*

<ROOT>

<AA>

<BB>

<CC/>

</BB>

<DD/>

</AA>

<AA>

<BB/>

</AA>

</ROOT>

XPath : /ROOT/descendant-or-self::CC

<ROOT>

<AA>

<BB>

<CC/>

</BB>

<DD/>

</AA>

<AA>

<BB/>

</AA>

</ROOT>

XPath : /CC/descendant-or-self::CC

<CC>

<AA>

<BB>

<CC/>

</BB>

<DD/>

</AA>

<AA>

<BB/>

</AA>

</CC>

L'axe des ancêtres fonctionne dans le sens inverse. Il s'écrit ancestor:: comme pour descendant, il existe une version ancestor-or-self::

XPath : /ROOT/*/*/ancestor::*

<ROOT>

<AA>

<BB>

<CC/>

</BB>

<DD/>

</AA>

<AA>

<BB/>

</AA>

</ROOT>

XPath : /ROOT/*/*/ancestor::AA

<ROOT>

<AA>

<BB>

<CC/>

</BB>

<DD/>

</AA>

<AA>

<BB/>

</AA>

</ROOT>

XPath : /ROOT/*/*/ancestor-or-self::*

<ROOT>

<AA>

<BB>

<CC/>

</BB>

<DD/>

</AA>

<AA>

<BB/>

</AA>

</ROOT>

IV-D - Précédent/suivant

Par l'axe preceding::, on sélectionnera tous les nœuds précédant - hors ancêtres - le nœud en lecture.

XPath : //EE/preceding::*

<ROOT>

<AA>

<BB>

<CC/>

</BB>

<DD/>

</AA>

<AA>

<EE/>

</AA>

</ROOT>

XPath : //EE/preceding::BB

<ROOT>

<AA>

<BB>

<CC/>

</BB>

<DD/>

</AA>

<AA>

<EE/>

</AA>

</ROOT>

Par l'axe following::, on sélectionnera tous les nœuds suivant - hors descendants et ancêtres - le nœud en lecture.

XPath : //BB/following::*

<ROOT>

<AA>

<BB>

<CC/>

</BB>

<DD/>

</AA>

<AA>

<EE/>

</AA>

</ROOT>

XPath : //BB/following::EE

<ROOT>

<AA>

<BB>

<CC/>

</BB>

<DD/>

</AA>

<AA>

<EE/>

</AA>

</ROOT>

IV-E - Frères

Enfin après tous ces axes, il existe aussi la notion de « frères » en XPath, même si cette dernière ne se fait que selon deux axes :

les « frères » précédents par l'axe preceding-sibling::

les « frères » suivants par l'axe following-sibling::

XPath : //BB/following-sibling::*

<ROOT>

<AA>

<BB>

<CC/>

</BB>

<DD/>

</AA>

<AA>

<EE/>

</AA>

</ROOT>

XPath : //DD/preceding-sibling::*

<ROOT>

<AA>

<BB>

<CC/>

</BB>

<DD/>

</AA>

<AA>

<EE/>

</AA>

</ROOT>

IV-F - Les attributs

Pour sélectionner des attributs par XPath, on utilisera l'axe attribute::* dont le raccourci est @*.

Si on désire tester un nom d'attribut : attribute::nom_attribut dont le raccourci est @nom_attribut .

XPath : //@*

<ROOT>

<AA>

<BB test1='1' >

<CC/>

</BB>

<DD/>

</AA>

<AA test2='1' >

< BB/>

</AA>

</ROOT>

XPath : //@test2

<ROOT>

<AA>

<BB test1='1'>

<CC/>

</BB>

<DD/>

</AA>

<AA test2='1' >

<BB/>

</AA>

</ROOT>

V - L'union

XPath permet de faire l'union entre deux XPath par l'opérateur « | »

XPath : //DD|//EE

<ROOT>

<AA >

<BB>

<CC/>

</BB>

<DD/>

</AA>

<AA>

<EE/>

</AA>

</ROOT>

VI - Le nodeset (collection de nœuds)

Comme nous l'avons vu précédemment un XPath peut renvoyer un type simple ou, un ou plusieurs nœuds. Dans ce dernier cas, le résultat se présente sous la forme d'une collection de nœuds : un nodeset.
Cette collection de nœuds est ordonnée de deux manières possibles :

- dans l'ordre (DDG) du document ;

- dans l'ordre exactement contraire.

Tout dépend des axes utilisés ; les axes ancestors, preceding et preceding-sibling construisent un nodeset dans l'ordre contraire, tous les autres suivent l'ordonnancement DDG.
Une particularité de l'union est de toujours réorganiser les nodesets des XPath concernés en un seul nodeset ordonné DDG, quel que soit l'ordonnancement des nodesets originaux.