Exemple 52. Un premier document pour XPath
<?xml version="1.0" encoding="UTF-8"?> <marin id="12"> <nom>Surcouf</nom> <prenom>Robert</prenom> <remarque lang="FR">Capitaine corsaire</remarque> </marin>
marin
, possédant un attribut
id
et trois sous-éléments.
nom
, contenant du texte.
prenom
. Il est important de noter que l'ordre des sous-éléments a un sens en XML. Le sous-élément
prenom
suit le sous-élément
nom
.
remarque
.
Exemple 53. Exécution d'une première requête XPath
String xpath = "/marin" ; // Lecture du document XML, toute autre méthode est valide ! // le fichier marins.xml doit se trouver dans le répertoire xml // à la racine du projet Eclipse File file = new File("xml/marins.xml") ; InputStream stream = new FileInputStream(file) ; Document document = new SAXReader().read(stream) ; // exécution de la requête proprement dite List resultNodes = document.selectNodes(xpath) ;
resultNodes
La requête XPath que nous avons exécutée ici,
/marin
permet de sélectionner, s'il existe, le nœud racine
marin
. La liste
resultNode
contient donc un unique objet, de type
Element
(au sens Dom4J), qui modélise le nœud racine.
/marin
, la requête n'est formé que d'une seule étape :
marin
.
Tout d'abord, une requête XPath part d'un nœud particulier d'un document XML, qui est en général le nœud racine du document XML que l'on analyse. Une étape est alors formée de trois éléments. Notons que dans le code
document.selectNodes(xpath)
, c'est bien sur l'élément XML
document
que la requête est effectuée. Dans la suite nous allons parler du nœud d'où part la requête XPath, il s'agit bien du nœud pointé par cette variable.
La forme générale d'une requête XPath est la suivante.
marin
), son type (on recherche les attributs du nœud duquel on part, ou le contenu textuel de cet élément), ou par un élément de schéma.
child
: cet axe désigne les nœuds immédiatement enfant du nœud que l'on regarde. Par exemple
/marins/child::marin
désigne tous les nœuds
marin
du nœud parent
marins
. Seuls les nœuds directement enfant du nœud
marins
sont retournés.
descendant
: cet axe désigne l'ensemble des nœuds enfant du nœud que l'on regarde, directs ou indirects. Par exemple
/marin/descendant::marin
désigne tous les nœuds
marin
qui se trouvent sous le nœud
marins
, à toutes les profondeurs. La requête
/marin/descendant::*
désigne tous les nœuds enfants de
marin
, à tous les niveaux.
descendant-or-self
: cet axe désigne l'ensemble des nœuds enfant du nœud que l'on regarde, directs ou indirects, ainsi que le nœud sur lequel on se trouve.
attribute
: cet axe désigne les attributs du ou des nœuds que l'on regarde. Par exemple
/marins/attribute::id
désigne l'attribut
id
du nœud racine
marin
, s'il existe. La requête
/marins/marin/attribute::*
désigne l'ensemble des attributs de l'ensemble des nœuds
marin
du nœud
marins
.
self
: désigne le nœud sur lequel on se trouve.
following
: désigne le nœud qui suit celui sur lequel on se trouve, spécifié par son nom. Par exemple
/marins/marin[attribute::id='5']/following::nom
commence par sélectionner le nœud
marin
dont l'attribut
id
vaut 5. Si ce nœud existe bien, alors le nœud
nom
qui suit est sélectionné, quel que soit son niveau par rapport au nœud
marin
. Ce nœud
nom
peut donc être lui-même enfant d'un frère du premier nœud
marin
.
following-sibling
: fonctionne de la même façon que l'axe
following
. La différence est que le nœud sélectionné est doit être frère du nœud dont on part. Dans notre exemple précédent, si l'on remplace
following
par
following-sibling
, alors ne peuvent être retournés que les nœuds
nom
qui se trouvent au même niveau que le nœud
marin
initialement sélectionné.
parent
: cet axe contient l'ensemble des nœuds parent du nœud que l'on regarde, jusqu'au nœud racine. Par exemple, la requête
//nom[text()='Tabarly']/parent::*
commence par sélectionner le nœud
nom
dont le contenu textuel a pour valeur
Tabarly
. Partant de ce nœud, elle sélectionne ensuite le parent direct de ce nœud.
ancestor
: cet axe contient l'ensemble des nœuds parent du nœud que l'on regarde, jusqu'au nœud racine. Il ne contient pas le nœud que l'on regarde. Par exemple, la requête
//nom[text()='Tabarly']/ancestor::*
désigne l'ensemble des nœuds parent du nœud
nom
dont le contenu textuel est
Tabarly
. Si l'on remplace
*
par
marin
, seuls les nœuds dont le nom est
marin
seront retournés dans cette hiérarchie.
ancestor-or-self
: cet axe contient l'ensemble des nœuds parent du nœud que l'on regarde, jusqu'au nœud racine. Il contient également le nœud que l'on regarde. Dans le cas de la requête précédente, le nœud sur lequel on se trouve est également retourné.
preceding
: cet axe est l'inverse de l'axe
following
. Il désigne les nœuds qui précède le nœud que l'on regarde, ainsi que leurs descendants.
preceding-sibling
: cet axe est l'inverse de l'axe
following-sibling
. Il désigne les nœuds qui précède le nœud que l'on regarde, mais uniquement au même niveau.
//marin[1]/nom/text()
retourne le contenu textuel du sous-élément
nom
de l'élément
marin
dont l'attribut
id
a pour valeur 1.
Les différentes fonctions que l'on peut passer à cette définition sont les suivantes.
document-node()
element()
attribute()
schema-element()
schema-attribute()
processing-instruction()
comment()
text()
namespace-node()
node()
//nom[text()='Tabarly']
. Les prédicats peuvent s'écrire de nombreuses façons, par exemple, le prédicat
//marin[age > 18 and age < 30]
sélectionne les éléments
marin
qui possède un sous-élément
age
, dont la valeur est comprise entre 18 et 30.
Node
NodeList
Element
Attr
CharacterData
Comment
CDATASection
Text
Entity
EntityReference
ProcessingInstruction
Document
DocumentFragment
DocumentType