3. Présentation de l'API

3.1. Interface ContentHandler

Cette interface comporte 11 méthodes. Voyons ici les principales.
  • startDocument() et endDocument() : appelées lorsqu’un début ou une fin de document est rencontrée ;
  • startElement() et endElement() : appelées lorsqu’un début ou une fin d’élément est rencontrée.
  • characters() : appelée quand un contenu de type PCDATA est rencontré.
  • setDocumentLocator() : appelée pour passer un objet de type Locator, que nous allons voir dans la suite.
Ces cinq méthodes permettent d’analyser simplement la plupart des documents XML. Voyons leur fonctionnement un peu plus en détails, notamment les arguments qu’elles reçoivent.

3.1.1. Méthodes startDocument() et endDocument()

La méthode startDocument() est appelée une fois lorsqu’un début de document est rencontré. Elle ne reçoit aucun paramètre. La méthode endDocument() est appelée une fois que l’analyse du document est entièrement terminée. Elle est appelée même si une erreur s’est produite lors de l’analyse.

3.1.2. Méthodes startElement() et endElement()

Ces deux méthodes sont appelées au début et à la fin de l’analyse d’un élément. Elles reçoivent toutes deux les trois paramètres suivants :
  • uri, localName : deux chaînes de caractères qui contiennent l’URI de l’espace de noms si elle existe, et le nom dans cette URI, sans préfixe.
  • qName : une chaîne de caractères qui contient le nom complet ( fully qualified name ), en général avec un préfixe.
La méthode startElement() reçoit en plus un objet de type Attributes, qui contient les attributs de cet élément.

3.1.3. Objet de type Attributes

L’objet de type Attributes fonctionne un peu comme un tableau. On peut regretter qu’il n’utilise aucune des interfaces de type Collection, à la différence de DOM4J. On peut obtenir le nombre d’attributs par la méthode getLength(), puis parcourir les noms de ces attributs par les méthodes getLocalName(i) et getQName(i), et leurs valeurs par la méthode getValue(i).

3.1.4. Objet de type Locator

Notons tout d’abord que cette méthode setLocator() est appelée par l’analyseur SAX pour passer à notre implémentation un objet de type Locator. Le type Locator est bien sûr une interface, dont voici les méthodes. L’objet Locator permet de retrouver le document XML analysé. Cet objet permet d’accéder à trois types d’information :
  • getColumnNumber() et getLineNumber() : donne les coordonnées du point (le numéro de la ligne et de la colonne dans le fichier texte) auquel l’événement a eu lieu dans le document XML.
  • getPublicId() : renvoie une chaîne de caractères qui contient l’identificateur public (URN) de l’élément dans lequel se trouve la balise qui a généré l’événement.
  • getSystemId() : renvoie l’identificateur système (URL) de l’entité qui contient l’élément qui a généré l’événement.

3.1.5. Méthode characters()

Cette méthode est appelée quand le contenu d’un élément est rencontré. L’analyseur lui passe en paramètres un tableau de type char [], suivi d’un offset et d’une longueur, tous deux de type int. Les données à lire sont les caractères référencés par cet offset et cette longueur. Le contenu de l’élément est envoyé morceau par morceau, au gré de l’analyseur. La seule chose garantie est que le contenu d’un morceau donné ne vient que d’une seule source, ce qui permet d’avoir un Locator cohérent. Pourquoi ne pas retourner tout le contenu textuel d'un élément en une seule fois ? Tout simplement parce que SAX est conçu pour lire des flux, et que ces flux peuvent eux-mêmes être disponibles au compte-gouttes.

3.1.6. Méthode ignorableWhiteSpace()

Cette méthode est appelée quand l’analyseur XML rencontre des caractères de type espace , qui peuvent être des espaces, des tabulations, des retours-chariot, etc… et qu’il choisit de les ignorer.

3.1.7. Méthode processingInstruction()

Cette méthode permet de récupérer une instruction dans un document XML. Une instruction XML a la syntaxe suivante.

Exemple 46. Exemple d'instruction XML

<?org.galilee.sql.ExecuteQuery sql="select * from Marins"?>

La méthode processingInstruction() reçoit en paramètre deux chaînes de caractères :
  • target : l’application-cible, ici ce qui peut être interprété comme une classe Java : org.galilee.sql.ExecuteQuery ;
  • data : l’argument de cette instruction, ici sql="select * from Marins".
Il est donc possible par ce biais de déclencher toute sorte d’opérations lors de l’analyse du document XML, ici une requête SQL sur une base de données.

3.2. Interface ErrorHandler

Il est possible, à la création de l’analyseur, de préciser s’il doit être validant ou non-validant. Si l’on choisit de créer un analyseur non-validant, des exceptions ne seront jetées qu’en cas de document XML mal formé. Si l’on a choisi un analyseur validant, alors les exceptions seront jetées en cas d’invalidité du document, c’est à dire de non-conformité aux déclarations d’une DTD ou de tout autre schéma passé en paramètre du document XML. Il y a trois niveaux d’erreur dans SAX :
  • les erreurs fatales : indiquent que le document est mal formé, et que l’analyseur ne peut plus continuer son travail ;
  • les erreurs simples : indiquent que le document est non-valide, en général l'analyseur peut tout de même continuer son travail ;
  • les alertes (warnings) : indiquent en général des informations qui doivent être portées à l’attention du développeur, telle que des doubles définitions dans une DTD.
Quand une erreur d’analyse est rencontrée, l’analyseur jette une exception de type SAXParseException. Cette classe contient notamment des méthodes qui permettent de trouver précisément l’endroit dans le document XML où l’erreur a été rencontrée. Les erreurs peuvent être captées aussi par événement, en implémentant cette interface. Elle contient trois méthodes : error(), fatalError() et warning(), toutes trois appelées avec le même argument, de type SAXParseException.

3.3. Interface DTDHandler

Les méthodes de cette interface sont appelées quand l’analyseur rencontre une entité non analysée , qui contient typiquement des données binaires. Ces données non-analysées sont définies par une notation. Par exemple, les deux lignes suivantes permettent de définir une image JPEG.

Exemple 47. Définition d’une notation JPEG, et utilisation

<!NOTATION  jpeg  SYSTEM  "viewer.exe">
 <!ENTITY  monImage  SYSTEM  "URL"  NDATA  "jpeg">

L’interface DTDHandler définit deux méthodes appelées sur ces deux lignes :
  • notationDecl() est une méthode appelée avec trois paramètres : le nom de la notation, son identificateur public et son identificateur système.
  • unparsedEntityDecl() est une méthode appelée avec les trois mêmes paramètres, plus un quatrième : le nom de la notation.
Bien sûr, au moins une des deux chaînes de caractères d’identification doit être non nulle.

3.4. Interface EntityResolver

Cette interface permet de mettre en œuvre un mécanisme de conversion d’URN en URL. Elle peut permettre de convertir une ressource de type "urn:/monServeur/maBase" en "http://192.168.1.80/base". L’unique méthode de cette interface, resolveEntity() renvoie un objet de type InputSource, qui peut être ouvert sur un document local au serveur. Voyons ceci sur un exemple.

Exemple 48. Association d’un URL à une URN par resolveEntity()

public InputSource resolveEntity(String publicId, String systemId) {
	 if (systemId.equals("http://www.galilee.org/unDocument")) {
		Reader r = 
			 new InputStreamReader(
				 new BufferedInputStream(
					 new FileInputStream(
						 new File("/fichiers/locaux/unDocument")))) ;
		InputSource is =  new InputSource(r) ;
	}  else {
		 return null ;
	}
}

3.5. Interface LexicalHandler

Les données caractères non-interprétées sont aussi appelées données lexicales dans le jargon XML. Elles sont gérées par une interface propre, LexicalHandler. Si l’on veut avoir accès aux données de type DTD et CDATA, il faut implémenter certaines des méthodes de cette interface. Les méthodes de cette interface fonctionnent exactement de la même façon que celles de ContentHandler : elles sont appelées lorsque l’analyseur rencontre la bonne balise. Passons ces méthodes en revue :
  • startDTD() et endDTD() : appelées sur le début de la DTD (le DOCTYPE) et sur sa fin. La méthode startDTD() reçoit en paramètres une première chaîne de caractères qui contient le nom du document, une deuxième chaîne qui contient l’identificateur public de la DTD externe, et une troisième qui contient l’identificateur système de la DTD externe.
  • startEntity() et endEntity() : appelées sur le début et la fin de la déclaration d’une entité ( ENTITY). La méthode statEntity() reçoit en paramètre le nom de l’entité.
  • startCDATA() et endCDATA() : appelées sur le début et la fin d’une section CDATA.
  • comment() : appelée lorsque l’analyseur rencontre un commentaire XML. Cette méthode reçoit en paramètres la chaîne de commentaires, dans un tableau de char, avec un offset et une longueur de chaîne.
Notons que cette interface n’est pas dans la liste des interfaces implémentées par DefaultHandler. Il reste une déclaration à faire si l’on veut que notre analyseur SAX envoie les événements que nous voulons capter vers notre gestionnaire lexical. Voyons ceci sur un exemple.

Exemple 49. Création d’un analyseur avec gestion lexicale

LexicalHandler lexicalHandler = … ;  // construction
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance() ;
saxParserFactory.setValidating(true) ;  // ou false si l'on veut un analyseur
                                        // non validant
SAXParser saxParser = saxParserFactory.newSAXParser() ;
XMLReader xmlReader = saxParser.getXMLReader() ;
xmlReader.setProperty(
      "http://xml.org/sax/properties/lexical-handler",
     lexicalHandler) ;  // déclaration standard
saxParser.parse(fichier XML, lexicalHandler) ;

La déclaration xmlr.setProperty("http://xml.org/sax/properties/lexical-handler", lexicalHandler) fait partie du standard SAX.
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