1. Notions générales

1-1. Objet

XPath 1.0 est un langage avec une syntaxe non-XML, permettant d'adresser les différents noeuds ou groupes de noeuds 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.

1-2. 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 noeud 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 noeuds XML: parents, fils, ancêtres...
    Par exemple :Child, parent, ancestor, self....
  • Un test : permet d'identifier le type du noeud 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 noeuds parcourus. Il est encadré par [ ] .

2. Types principaux

2-A. Mécanisme du typage en Xpath

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

  • les types de noeuds : 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.

2-B. Types de noeud

2-B-1. Vocabulaire

  • noeud parent : le ou les types de noeuds qui peuvent contenir celui-ci.
  • noeud fils : le ou les types de noeuds qu'on peut retrouver dans ce noeud.
  • expression xpath : les expressions xpath permettant de cibler ce type de noeud : test et/ou axe.
  • valeur textuelle : la valeur utilisée lors d'un affichage ou d'une comparaison.

2-B-2. Text (texte)

  • noeud parent : element
  • noeud fils : aucun
  • expression xpath : node() (test), text()(test)
  • valeur textuelle : la chaîne de caractères contenue

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

Elles sont elles aussi vues comme des noeuds.

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

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

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

Ici par exemple le noeud AAA contient trois noeuds texta, b et c

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

  • noeud parent : root, element
  • noeud 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 noeuds text qui sont ses descendants

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

 
Sélectionnez
<?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 noeuds de type element possèdent des noms. Le noeud 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.

2-B-4. Attribute (attribut)

  • noeud parent : element
  • noeud 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 =
 
Sélectionnez
<?xml version="1.0"?>
<racine>
    <AAA num="1"/>
</racine>

ici la valeur textuelle du noeud attributenum du noeud elementAAA est 1.

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

2-B-5. Root (racine)

  • noeud parent : aucun
  • noeud fils :element,comment,processing-instruction
  • expression xpath : node() (test), / (axe)
  • valeur textuelle : ensemble des contenus noeuds textes qui sont ses descendants.

Pour un XML du type

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

sa valeur textuelle est : bca.

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

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

  • noeud parent : element
  • noeud 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 noeuds via leur nom expansé à leur URI à un traitement particulier. Prenons par exemple une feuille XSLT :

 
Sélectionnez
<?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 noeud namespace est xmlns:xsl, sa valeur textuelle :http://www.w3.org/1999/XSL/Transform Tous les noeuds 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.

2-B-7. Comment (commentaire)

  • noeud parent : element, root
  • noeud 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.

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

Ce commentaire a pour valeur textuelle commentaires 1.

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

  • noeud parent : root
  • noeud fils : aucun
  • expression xpath : node()(test), processing-instruction() (test)
  • valeur textuelle : ce qui est contenu entre <? et ?>

Ces noeuds 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 noeud root. Il est donc impossible de récupérer l'encoding du document via Xpath.

2-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.

3. Test d'un noeud

Deux tests sont possibles sur un noeud 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é.

4. 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 « / ».

4-1. 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 noeuds 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>

4-2. 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>

4-3. Ancêtre/descendant

A 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 noeuds spécifiés contenus dans le noeud 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 noeud à 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>

4-4. Précédent/suivant

Par l'axe preceding::, on sélectionnera tous les noeuds précédant - hors ancêtres - le noeud 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 noeuds suivant - hors descendants et ancêtres - le noeud 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>

4-5. 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>

4-6. 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>

5. 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>

6. Le nodeset (collection de noeuds)

Comme nous l'avons vu précédemment un XPath peut renvoyer un type simple ou, un ou plusieurs noeuds. Dans ce dernier cas, le résultat se présente sous la forme d'une collection de noeuds : un nodeset.
Cette collection de noeuds 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.