Consommer un document XML, approche SAX

//
// Entrées/ sorties
//
import java.io.*;
//
// Utiliser SAX
//
import org.xml.sax.*;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;

//
// La classe DefaultHandler implémente des méthodes vides pour
// la plupart des événements SAX, puis nous surchargerons celles
// qui nous tiennent à coeur
//
public class ConsommateurSAX extends DefaultHandler {
   private static final String ENCODAGE = "ISO-8859-1";
   private static final String
      ENTÊTE_XML = "<?xml " +
                   "version='1.0' " +
                    "encoding='" +
                    ENCODAGE +
                    "'?>";
   private int m_Niveau;
   public static void main(String [] args) {
      if (args.length == 0) {
         System.err.println ("Usage: java AfficheurDOM fichierXML [fichierXML ...]");
      } else {
         for (String s : args) {
            ConsommateurSAX cs = new ConsommateurSAX ();
            cs.consommer (s);
         }
      }
   }
   private Writer m_Écrivain;
   public ConsommateurSAX () {
      m_Niveau = 0;
      try {
         m_Écrivain = new OutputStreamWriter(System.out, ENCODAGE);
      } catch (IOException ioe) {
         ioe.printStackTrace();
      }
   }
   public void consommer (String nomFich) {
      try {
         m_Écrivain.write ("Décodage du fichier " + nomFich + "\n");
         m_Écrivain.flush ();

         SAXParserFactory Fabrique = SAXParserFactory.newInstance();
         SAXParser AnalysteSAX = Fabrique .newSAXParser();
         AnalysteSAX.parse (new File(nomFich), this);
      } catch (SAXException sxe) {
         //
         // Erreurs de traitement du document
         //
         Exception ex =
            (sxe.getException() != null)? sxe.getException() : sxe;
         ex.printStackTrace();
      } catch (ParserConfigurationException pce) {
         //
         // Erreurs d'option de traitement
         //
         pce.printStackTrace();
      } catch (IOException ioe) {
         //
         // Erreurs générales d'entrée/ sortie
         //
         ioe.printStackTrace();
      }
   }
   //
   // Pour générer une sortie
   //
   private String générerIndentation () {
      final int NB_ESPACES_NIVEAU = 3;
      // inefficace mais bon...
      String ind = "";
      for (int i = 0; i < m_Niveau * NB_ESPACES_NIVEAU; ++i) {
         ind = ind + " ";
      }
      return ind;
   }
   private void émettre (String s) throws SAXException {
      try {
         m_Écrivain.write(s);
      } catch (IOException e) {
         throw new SAXException("Erreur d'entrée/ sortie: ", e);
      }
   }
   //
   // Projection d'un changement de ligne
   //
   private void nouvelleLigne () throws SAXException {
      émettre (System.getProperty("line.separator"));
   }
   //
   // Réaction à un début de document
   //
   public void startDocument () throws SAXException {
      émettre (ENTÊTE_XML);
      nouvelleLigne();
   }
   //
   // Réaction à une fin de document
   //
   public void endDocument() throws SAXException {
      try {
         nouvelleLigne ();
         m_Écrivain.flush();
      } catch (IOException e) {
         throw new SAXException("Erreur d'entrée/ sortie: ", e);
      }
   }
   //
   // Réaction à un début d'élément
   //
   public void startElement
      (String namespaceURI, String nomSimple, String nomQualifié,
       Attributes attrs) throws SAXException {
      émettre (générerIndentation ());
      ++m_Niveau;
      String nomÉlément = nomSimple;
      if ("".equals (nomÉlément)) { // pas de namespace
         nomÉlément = nomQualifié;
      }
      émettre ("<" + nomÉlément);
      if (attrs != null) {
         for (int i = 0; i < attrs.getLength(); i++) {
             String nomAttribut = attrs.getLocalName(i);
             if ("".equals(nomAttribut)) {
                nomAttribut = attrs.getQName(i);
             }
             émettre (" ");
             émettre (nomAttribut + "=\"" +attrs.getValue (i)+ "\"");
         }
      }
      émettre (">");
      nouvelleLigne ();
   }
   //
   // Réaction à une fin d'élément
   //
   public void endElement
      (String namespaceURI, String nomSimple, String nomQualifié) throws SAXException {
      --m_Niveau;
      émettre (générerIndentation () + "</" + nomQualifié + ">");
      nouvelleLigne ();
   }
   //
   // Pour voir le reste du texte consommé (génère l'indentation s'il y en a!)
   //
   public void characters(char buf[], int offset, int len) throws SAXException {
      String s = new String(buf, offset, len).trim ();
      if (! "".equals (s)) {
         émettre (générerIndentation () + s);
         nouvelleLigne();
      }
   }
}

Le code proposé à droite consomme un document XML selon une stratégie SAX et en fait une représentation indentée à la console.

Si vous examinez attentivement le tout, vous remarquerez que le code consommant le document y est plus petit que le code relié à l'affichage—consommer un document XML n'est pas une tâche très douloureuse, surtout en comparaison avec une tâche pleine de petits détails comme celle de gérer une interface personne/ machine.