Aller au contenu

Programmation XML/XPath

Un livre de Wikilivres.

Le XPath est un langage de sélection de différents types d'objets XML, appelés « nœuds »[1]. Un ensemble de nœuds est appelé « contexte ».

Le XPath se présente sous la forme de chemins composés de[2] :

Sélecteur Notes
nom du nœud Sélectionne ce qui est compris dans le nœud nommé.
/ Sélectionne en partant du nœud racine (chemin absolu).
// Sélectionne en partant du nœud courant, peu importe le reste de l'emplacement.
. Sélectionne à partir du nœud courant (chemin relatif). = self::node()
.. Sélectionne à partir du parent du nœud courant. = parent::node()
@ Sélectionne les attributs. = attribute::
| Opérateur de sélection multiple.
 Il existe un interpréteur en ligne pour réaliser les exemples décrits ci-dessous : http://www.xpathtester.com/.
La classe http://www.php.net/manual/fr/domxpath.query.php permet de les programmer.

Ces expressions sont appelées « chemin de localisation », composés d'un ou plusieurs « pas de localisation » (ou « étapes ») séparés par des « / ». Les pas de localisation ont chacun trois composants :

  1. Un axe (parent, descendant…).
  2. Un test de nœud (nom ou fonction désignant les nœuds).
  3. Des prédicats (entre crochets).

Pour décrire les relations entre les nœuds, XPath utilise le vocabulaire suivant :

Axe Abréviation Notes
ancestor ancêtre
ancestor-or-self ancêtre ou soi
attribute @ attribut, @abc signifie attribute::abc
child enfant, xyz signifie child::xyz
descendant
descendant-or-self // // signifie /descendant-or-self::node()/
following suivant
following-sibling frère suivant
namespace espace de noms
parent .. .. signifie parent::node()
preceding précédent
preceding-sibling
self . soi, . signifie self::node()

Tests de nœuds

[modifier | modifier le wikicode]

Soit l'espace de nom ns :

  • //ns:* sélectionne tous les éléments du namespace.
  • //ns:nom récupère tous les éléments du namespace nommés "nom".
Tests Notes
comment() trouve tous les commentaires (ex : <!-- commentaire 1 -->)
text() trouve un nœud texte, (ex : hello world dans <k>hello<m> world</m></k>)
processing-instruction() trouve les instructions de traitement (ex : //processing-instruction('php') trouve <?php echo $a; ?>)
node() trouve tous les nœuds.

Les prédicats sont des fonctions filtrant les nœuds évalués à false, qui se placent à la fin des sélections[3] :

Par exemple, les quatre requêtes ci-dessous renvoie le même résultat (si la branche 2 est la dernière comme dans l'exemple en bas de cette page) :

//branche[2]
//branche[@nom="branche2"]
/tronc/branche[last()]
/tronc/branche[position()=2]
Prédicats Notes
last() renvoie le dernier nœud de la sélection
position() renvoie le nœud situé à la position précisée
count(contexte) renvoie le nombre de nœuds en paramètre
starts-with(chaine1, sous-chaine2) renvoie true si le premier argument commence avec le second
contains(botte_de_foin, aiguille) renvoie true si le premier argument contient le second
sum(contexte) renvoie la somme des valeurs numériques des nœuds en paramètre
floor(nombre) renvoie le nombre arrondi à l'entier inférieur
ceiling(nombre) renvoie le nombre arrondi à l'entier supérieur
round(nombre) renvoie le nombre arrondi à l'entier le plus proche

Soit l'arborescence suivante :

<?xml version="1.0" encoding="UTF-8"?>
<tronc nom="tronc1"> 
	<!-- commentaire 1 --> 
	<branche nom="branche1" epaisseur="gros"> 
		<brindille nom="brindille1"> 
			<!-- commentaire 2 --> 
			<feuille nom="feuille1" couleur="marron" />
			<feuille nom="feuille2" poids="50" />
			<feuille nom="feuille3" /> 
		</brindille> 
		<brindille nom="brindille2">
			<feuille nom="feuille4" poids="90" /> 
			<feuille nom="feuille5" couleur="violet" />   
		</brindille>
	</branche> 
	<branche nom="branche2">
		<brindille nom="brindille3"> 
			<feuille nom="feuille6" /> 
		</brindille> 
		<brindille nom="brindille4">	
			<feuille nom="feuille7" /> 
			<feuille nom="feuille8" /> 
			<feuille nom="feuille9" couleur="noir" /> 
			<feuille nom="feuille10" poids="100" />	 
		</brindille>
	</branche> 
	<branche nom="branche3">
		<brindille nom="brindille5"> 
		</brindille> 
	</branche> 
</tronc>
  • Sélection 1 : toutes les <feuille> d'une <brindille> contenue dans une <branche>, descendant du <tronc>, issu de la racine.
    1. Abrégé : /tronc/branche/brindille/feuille
    2. Non abrégé : /child::tronc/child::branche/child::brindille/child::feuille
  • Sélection 2 : la <branche> dont l'attribut "nom" est "branche3", enfant du <tronc>, inclue dans la racine.
    1. Abrégé : /tronc/branche[@nom='branche3']
    2. Non abrégé : /child::tronc/child::branche[attribute::nom='branche3']
  • Sélection 3 : toutes les brindilles ont au moins une feuille.
    1. //brindille[feuille]
  • Sélection 4 : dernière branche du tronc.
    1. //tronc/branche[last()]
  • Sélection 5 : tous les noms des brindilles qui n'ont pas de feuille.
    1. //brindille[not(feuille)]/@nom

Créer le .php suivant à côté du tronc.xml publié ci-dessus.

<?php
  $file = 'tronc.xml';
  $xpath = "/tronc/branche/brindille/feuille[last()]";
  if(file_exists($file)) {
    $xml = simplexml_load_file($file);
    if($result = $xml->xpath($xpath)) {
		print 'Résultats :';
		var_dump($result);
    } else {
      echo 'Syntaxe invalide.';
	}
  }
  else
    exit("Le fichier $file n'existe pas.");
?>
Pour plus de détails voir : XQuery.
  1. http://www.w3schools.com/dom/dom_nodetype.asp
  2. http://www.w3schools.com/xpath/xpath_syntax.asp
  3. http://www.w3.org/TR/xpath#corelib