Chapitre 12. Programmation XML

Pages des sources des examples.

Il existe deux méthodes essentielles appelées SAX et DOM pour lire un document XML dans un fichier. Il en existe en fait une troisième appelée StAX qui n'est pas abordée ici.

12.1. SAX

12.1.1. Principe

Principe de SAX

Figure 12.1. Principe de SAX


SAX est une API permettant de lire un fichier XML sous forme de flux. Le principe de fonctionnent est le suivant. L'application crée un parseur et elle enregistre auprès de ce parseur son gestionnaire d'événements. Au cours de la lecture du fichier contenant le document XML, le gestionnaire reçoit les événements générés par la parseur. Le document XML n'est pas chargé en mémoire.

La tâche du programmeur est légère puisque le parseur est fourni par l'environnement Java. Seul le gestionnaire d'événements doit être écrit par le programmeur. Cette écriture est facilitée par les gestionnaires par défaut qu'il est facile de dériver pour obtenir un gestionnaire.

12.1.2. Lecture d'un fichier XML avec SAX

Handler TrivialSAXHandler.java minimal

import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.helpers.DefaultHandler;

/**
 * Handler trivial pour SAX
 * Ce handler se contente d'afficher les balises ouvrantes et fermantes.
 * @author O. Carton
 * @version 1.0
 */
class TrivialSAXHandler extends DefaultHandler {
   public void setDocumentLocator(Locator locator) {
       System.out.println("Location : " + 
			  "publicId=" + locator.getPublicId() + 
			  " systemId=" + locator.getSystemId());
   }
   public void startDocument() {
       System.out.println("Debut du document");
   }
   public void endDocument() {
       System.out.println("Fin du document");
   }
   public void startElement(String namespace, 
			    String localname,
			    String qualname,
			    Attributes  atts) {
       System.out.println("Balise ouvrante : " + 
			  "namespace=" + namespace + 
			  " localname=" + localname + 
			  " qualname=" + qualname);
   }
   public void endElement(String  namespace, 
			  String localname,
			  String qualname) {
       System.out.println("Balise fermante : " + 
			  "namespace=" + namespace + 
			  " localname=" + localname + 
			  " qualname=" + qualname);
   }
   public void characters(char[] ch, int start, int length) {
       System.out.print("Caractères : ");
       for(int i = start; i < start+length; i++)
	   System.out.print(ch[i]);
       System.out.println();
   }
}

Lecture TrivialSAXRead.java d'un fichier XML

// IO
import java.io.InputStream;
import java.io.FileInputStream;
// SAX
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.SAXParser;

/**
 * Lecture triviale d'un document XML avec SAX
 * @author O. Carton
 * @version 1.0
 */
class TrivialSAXRead {
   public static void main(String [] args)
       throws Exception
   {
       // Création de la fabrique de parsers
       SAXParserFactory parserFactory = SAXParserFactory.newInstance();
       // Création du parser
       SAXParser parser = parserFactory.newSAXParser();

       // Lecture de chaque fichier passé en paramètre
       for(int i = 0; i < args.length; i++) {
	   // Flux d'entrée
	   InputStream is = new FileInputStream(args[i]);
	   parser.parse(is, new TrivialSAXHandler());
       }
   }
}

12.2. DOM

12.2.1. Principe

Principe de DOM

Figure 12.2. Principe de DOM


DOM est une API permettant de charger un document XML sous forme d'un arbre qu'il est ensuite possible de manipuler. Le principe de fonctionnent est le suivant. L'application crée un constructeur qui lit le document XML et construit une représentation du document XML sous forme d'un arbre.

12.2.2. Arbre document

<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Time-stamp: "tree.xml  14 Feb 2008 09:29:00" -->
<?xml-stylesheet href="tree.xsl" type="text/xsl"?> 
<table type="technical">
 <item key="id001" lang="fr">
   XML &amp; Co
 </item>
 <item>
   <!-- Un commentaire inutile -->
   Du texte
 </item>
 et encore du texte.
</table>

La figure ci-dessous représente sous forme d'arbre le document XML présenté ci-dessus.

Arbre d'un document

Figure 12.3. Arbre d'un document


12.2.3. Principales classes

Classes du DOM

Figure 12.4. Classes du DOM


12.2.4. Lecture d'un fichier XML avec DOM

Lecture TrivialDOMRead.java d'un fichier XML

// IO
import java.io.InputStream;
import java.io.FileInputStream;
// DOM
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import org.w3c.dom.Document;

/**
 * Lecture triviale d'un document XML avec DOM
 * @author O. Carton
 * @version 1.0
 */
class TrivialDOMRead {
   public static void main(String [] args)
       throws Exception
   {
       // Création de la fabrique de constructeur de documents
       DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
       // Création du constructeur de documents
       DocumentBuilder documentBuilder = dbf.newDocumentBuilder();

       // Lecture de chaque fichier passé en paramètre
       for(int i = 0; i < args.length; i++) {
	   // Flux d'entrée
	   InputStream is = new FileInputStream(args[i]);
	   // Construction du document
	   Document doc = documentBuilder.parse(is);
	   // Exploitation du document ...
	   System.out.println(doc);
       }
   }
}

12.3. Comparaison

La grande différence entre les API, SAX et DOM est que la première ne charge pas le document en mémoire alors que la seconde construit en mémoire une représentation arborescente du document. La première est donc particulièrement adaptée aux (très) gros documents. Par contre, elle offre des facilités de traitement plus réduites. Le fonctionnement par événements rend difficiles des traitements non linéaires du document. Au contraire, l'API DOM rend plus faciles des parcours de l'arbre.

12.4. AJAX

Cette page donne un petit historique de l'objet XMLHttpRequest.

<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
	 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" >
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr">
<head>
 <title>
 Chargement dynamique
 </title>
 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
 <meta name="Author" content="Olivier Carton" />
 <script type="text/javascript">
   // Dans la première version de Google Suggest, la fonction
   // s'appelait sendRPCDone.  Elle s'appelle maintenant 
   // window.google.ac.Suggest_apply
   window.google = new Object();
   window.google.ac = new Object();
   window.google.ac.Suggest_apply = sendRPCDone;

   var XMLHttpRequestObject = false;
   // Création du gestionnaire de connexion
   if (window.XMLHttpRequest) {
     XMLHttpRequestObject = new XMLHttpRequest();
   } else {
     XMLHttpRequestObject = new ActiveXObject("Microsoft.XMLHTTP");
   }

   // Fonction de chargement des données
   function getData(url) {
     if (XMLHttpRequestObject) {
       // Mise en place de la requête
       XMLHttpRequestObject.open("GET", url);

       // Mise en place du handler
       XMLHttpRequestObject.onreadystatechange = function() {
	 if (XMLHttpRequestObject.readyState == 4 &&
	     XMLHttpRequestObject.status == 200) {
	       // Évaluation du résultat
	       eval(XMLHttpRequestObject.responseText);
	 }
       }
       // Envoi de la requête
       XMLHttpRequestObject.send(null);
     }
   }

   // Fonction appelée à chaque entrée de caractère
   function getSuggest(keyEvent) {
     var keyEvent = (keyEvent) ? keyEvent : window.event;
     var input = (keyEvent.target) ? keyEvent.target : keyEvent.srcElement;
     // Utilisation du wrapper google.php
     var url = "google.php?qu=";

     if (keyEvent.type == 'keyup') {
       if (input.value) {
	 getData(url + input.value);
       } else {
	 var target = document.getElementById("target");
	 target.innerHTML = "<div></div>";
       }
     }
   }

   // Fonction appelée par la requête
   function sendRPCDone(unused, term, results, unusedArray) {
     // Entête de la table de présentation des résultats
     var data = "<table align='left' border='1' " + 
		"cellpadding='2' cellspacing='0'>";
     if (results.length != 0) {
       for (var i = 1; i < results.length-1; i = i + 2) {
	  data += "<tr><td><a href='http://www.google.com/search?q=" + 
		  results[i] + "'>" + results[i] + "</a></td>" + 
		  "<td>" + results[i+1] + "</td></tr>";
       }          
     }
     data += "</table>";
     var target = document.getElementById("target");
     target.innerHTML = data;
   }
 </script>
</head>

<body>
<h2>Google Live Search</h2>
 <!-- Zone de saisie -->
 <!-- La fonction getSuggest est appelée à chaque touche relachée -->
 <p><input type="text" onkeyup="JavaScript:getSuggest(event)" /></p>
 <!-- Div recevant le résultat -->
 <p><div id="target"></div></p>
</body>
</html>