2. Une première requête XPath

2.1. Un premier document à interroger

Une requête XPath doit être appliquée à un document XML. La première chose que nous devons faire est donc de prendre un tel document qui va nous servir de terrain de jeu. Reprenons donc l'exemple du début de ce cours.

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>

Rappelons tout d'abord la structure de ce document, du point de vue XML. Ce document est composé des éléments suivants :
  • D'un élément racine, marin, possédant un attribut id et trois sous-éléments.
  • D'un premier sous-élément, nom, contenant du texte.
  • D'un deuxième sous-élément, 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.
  • D'un troisième sous-élément remarque.

2.2. Une première requête

Écrivons une première requête sur le document XML précédent, et passons-la à Dom4J pour l'exécuter.

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) ;

Une fois le resultat calculé, une liste d'éléments XML est retournée, ici dans la variable 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.

2.3. Forme d'une requête XPath

Une requête XPath est formé d'étapes. Dans notre exemple précédent /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.

Exemple 54. Forme générale d'une requête XPath

axis::node_definition[predicate]

Cette requête est formée de trois éléments.
  • Un axe, qui représente la direction dans laquelle on recherche le nœud spécifié.
  • La définition du nœud XML que l'on cherche. Ce nœud peut être désigné par son nom (on recherche les éléments 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.
  • Un prédicat, qui permet de tester si le nœud que l'on regarde a une valeur particulière.

2.3.1. Définition de l'axe

L'axe de la recherche peut être dans le sens descendant (du nœud vers ses enfants) ou ascendant (du nœud vers ses parents). Les axes descendants sont les axes suivants.
  • 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é.
Les axes ascendants sont les axes suivants.
  • 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.

2.3.2. Définition du nœud

La façon la plus simple de définir un nœud est de donner son nom, comme nous l'avons fait dans les exemples du paragraphe précédent. Si ce nom peut correspondre à un élément XML, ou à un attribut. Il peut aussi correspondre à un élément textuel. Par exemple, la requête suivante //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()

2.3.3. Définition du prédicat

Le prédicat est le dernier élément d'une requête XPath. Un prédicat est écrit entre crochet. Nous avons en fait déjà écrit une requête XPath qui comportait un prédicat : //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.
API Java pour XML
Retour au blog Java le soir
Cours & Tutoriaux
Table des matières
Introduction
1. Un peu d'histoire
2. Les API Java pour XML
Un premier exemple
1. Introduction
2. Structure de base d’un fichier XML
2.1. Un fichier XML simple
2.2. Notion d’espaces de noms
3. Un premier code pour lire un fichier XML
3.1. Lecture avec Dom4J
Description d’un document XML
1. Introduction
2. Organisation d'un document XML
2.1. Introduction
2.2. Nœuds dans un document XML
2.3. Relations entre nœuds dans un document XML
2.4. Ordre dans un document
2.5. Valeurs atomiques dans un document XML
2.6. Notion de PCDATA et CDATA
3. Document Type Definition (DTD)
3.1. Attacher un document à une DTD
3.2. Contenu d’une DTD
3.3. Exemple de DTD, analyse de web-app_2_3.dtd
4. XML Schema
4.1. Introduction
4.2. Un premier schéma
4.3. Attacher un document XML à un schéma
4.4. Types simples
4.5. Attribut
4.6. Restriction sur une déclaration
4.7. Types complexes
4.8. Contraindre un contenu simple
Lire et écrire du XML
1. Introduction
2. Utilisation de DOM4J
2.1. Introduction
2.2. Un premier exemple simple
2.3. Organisation de l'API
2.4. Classe Namespace
2.5. Classe QName
2.6. Interface Node
2.7. Interface Branch
2.8. Interface Document
2.9. Interface Element
2.10. Interface Attribute
2.11. Interface Text
3. Utilisation de Xerces
3.1. Introduction
3.2. Présentation de SAX
3.3. Présentation de DOM
Analyseur SAX en Xerces
1. Introduction
2. Création d'un analyseur SAX
2.1. Introduction
2.2. Objet DefaultHandler
2.3. Exemple d'analyse d'un fichier
3. Présentation de l'API
3.1. Interface ContentHandler
3.2. Interface ErrorHandler
3.3. Interface DTDHandler
3.4. Interface EntityResolver
3.5. Interface LexicalHandler
Manipuler un DOM en Xerces
1. Introduction
2. Création d'un DOM
3. Présentation de l'API
3.1. Organisation de l'API
3.2. Interface Node
3.3. Interface NodeList
3.4. Interface Element
3.5. Interface Attr
3.6. Interface CharacterData
3.7. Interface Comment
3.8. Interface CDATASection
3.9. Interface Text
3.10. Interface Entity
3.11. Interface EntityReference
3.12. Interface ProcessingInstruction
3.13. Interface Document
3.14. Interface DocumentFragment
3.15. Interface DocumentType
Interroger un document en XPath
1. Introduction, notion de nœud XML
2. Une première requête XPath
2.1. Un premier document à interroger
2.2. Une première requête
2.3. Forme d'une requête XPath