Developpez.com - Java
X

Choisissez d'abord la catégorieensuite la rubrique :

 

Développons en Java   2.10  
Copyright (C) 1999-2016 Jean-Michel DOUDOUX    (date de publication : 19/03/2016)

[ Précédent ] [ Sommaire ] [ Suivant ] [Télécharger ]      [Accueil ]

 

42. SAX (Simple API for XML)

 

chapitre 4 2

 

Niveau : niveau 3 Intermédiaire 

 

SAX est l'acronyme de Simple API for XML. Cette API a été développée par David Megginson.

Ce type de parseur utilise des événements pour piloter le traitement d'un fichier XML. Un objet (nommé handler en anglais) doit implémenter des méthodes particulières définies dans une interface de l'API pour fournir les traitements à réaliser : selon les événements, le parseur appelle ces méthodes.

Les dernières informations concernant cette API sont disponible à l'URL : www.megginson.com/SAX/index.html

Les classes de l'API SAX sont regroupées dans le package org.xml.sax

Ce chapitre contient plusieurs sections :

 

 

42.1. L'utilisation de SAX de type 1

SAX type 1 est composé de deux packages :

SAX définit plusieurs classes et interfaces :

Les exemples de cette section utilisent la version 2.0.15 du parseur xml4j d'IBM.

Pour parser un document XML avec un parseur XML SAX de type 1, il faut suivre les étapes suivantes :

Exemple : avec XML4J
import org.xml.sax.*;
import org.xml.sax.helpers.ParserFactory;
import com.ibm.xml.parsers.*;
import java.io.*;

public class MessageXML {
  static final String DONNEES_XML =
    "<?xml version=\"1.0\"?>\n"
    +"<BIBLIOTHEQUE>\n"
    +"  <LIVRE>\n"
    +"    <TITRE>titre livre 1</TITRE>\n"
    +"    <AUTEUR>auteur 1</AUTEUR>\n"
    +"    <EDITEUR>editeur 1</EDITEUR>\n"
    +"  </LIVRE>\n"
    +"  <LIVRE>\n"
    +"    <TITRE>titre livre 2</TITRE>\n"
    +"    <AUTEUR>auteur 2</AUTEUR>\n"
    +"    <EDITEUR>editeur 2</EDITEUR>\n"
    +"  </LIVRE>\n"
    +"  <LIVRE>\n"
    +"    <TITRE>titre livre 3</TITRE>\n"
    +"    <AUTEUR>auteur 3</AUTEUR>\n"
    +"    <EDITEUR>editeur 3</EDITEUR>\n"
    +"  </LIVRE>\n"
    +"</BIBLIOTHEQUE>\n";

  static final String CLASSE_PARSER = "com.ibm.xml.parsers.SAXParser";

  /**
   * Lance l'application.
   * @param args un tableau d'arguments de la ligne de commandes
   */
  public static void main(java.lang.String[] args) {
  
    MessageXML m = new MessageXML();
    m.parse();

    System.exit(0);
  }

  public MessageXML() {
    super();
  }

  public void parse() {
    TestXMLHandler handler = new TestXMLHandler();
  
    System.out.println("Lancement du parseur");

    try {
      Parser parser = ParserFactory.makeParser(CLASSE_PARSER);

      parser.setDocumentHandler(handler);
      parser.setErrorHandler((ErrorHandler) handler);

      parser.parse(new InputSource(new StringReader(DONNEES_XML)));

    } catch (Exception e) {
      System.out.println("Exception capturée : ");
      e.printStackTrace(System.out);
      return;
    }
  }
}

 

Il faut ensuite créer la classe du handler.

Exemple :
import java.util.*;

/**
 * Classe utilisée pour gérer les événements émis par SAX lors du traitement du fichier XML
 */
public class TestXMLHandler extends org.xml.sax.HandlerBase {
  public TestXMLHandler() {
    super();
  }
  
  /**
   * Actions à réaliser sur les données
   */
  public void characters(char[] caracteres, int debut, int longueur) {
    String donnees = new String(caracteres, debut, longueur);
    System.out.println("   valeur = *" + donnees + "*");
  }
  
  /**
   * Actions à réaliser lors de la fin du document XML.
   */
  public void endDocument() {
    System.out.println("Fin du document");
  }
  
  /**
   * Actions à réaliser lors de la détection de la fin d'un élément.
   */
  public void endElement(String name) {
    System.out.println("Fin tag " + name);
  }
  
  /**
   * Actions à réaliser au début du document.
   */
  public void startDocument() {
    System.out.println("Debut du document");
  }
  
  /**
   * Actions à réaliser lors de la détection d'un nouvel élément.
   */
  public void startElement(String name, org.xml.sax.AttributeList atts) {
    System.out.println("debut tag : " + name);
  }
}
Résultat :
Lancement du parser
Debut du document
debut tag : BIBLIOTHEQUE
   valeur = *
  *
debut tag : LIVRE
   valeur = *
    *
debut tag : TITRE
   valeur = *titre livre 1*
Fin tag TITRE
   valeur = *
    *
debut tag : AUTEUR
   valeur = *auteur 1*
Fin tag AUTEUR
   valeur = *
    *
debut tag : EDITEUR
   valeur = *editeur 1*
Fin tag EDITEUR
   valeur = *
  *
Fin tag LIVRE
   valeur = *
  *
debut tag : LIVRE
   valeur = *
    *
debut tag : TITRE
   valeur = *titre livre 2*
Fin tag TITRE
   valeur = *
    *
debut tag : AUTEUR
   valeur = *auteur 2*
Fin tag AUTEUR
   valeur = *
    *
debut tag : EDITEUR
   valeur = *editeur 2*
Fin tag EDITEUR
   valeur = *
  *
Fin tag LIVRE
   valeur = *
  *
debut tag : LIVRE
   valeur = *
    *
debut tag : TITRE
   valeur = *titre livre 3*
Fin tag TITRE
   valeur = *
    *
debut tag : AUTEUR
   valeur = *auteur 3*
Fin tag AUTEUR
   valeur = *
    *
debut tag : EDITEUR
   valeur = *editeur 3*
Fin tag EDITEUR
   valeur = *
  *
Fin tag LIVRE
   valeur = *
*
Fin tag BIBLIOTHEQUE
Fin du document

Un parseur SAX peut créer plusieurs types d'événements. Les principales méthodes pour y répondre sont :

Evénement

Rôle

startElement()

cette méthode est appelée lors de la détection d'un tag de début

endElement()

cette méthode est appelée lors de la détection d'un tag de fin

characters()

cette méthode est appelée lors de la détection de données entre deux tags

startDocument()

cette méthode est appelée lors du début du traitement du document XML

endDocument()

cette méthode est appelée lors de la fin du traitement du document XML

La classe handler doit redéfinir certaines de ces méthodes selon les besoins des traitements.

En règle générale :

La sauvegarde du tag courant est obligatoire car la méthode characters() ne contient pas dans ses paramètres le nom du tag correspondant aux données.

Si les données contenues dans le document XML contiennent plusieurs occurrences qu'il faut gérer avec une collection qui contiendra des objets encapsulant les données, il faut :

La méthode characters() est appelée lors de la détection de données entre un tag de début et un tag de fin mais aussi entre un tag de fin et le tag de début suivant lorsqu'il y a des caractères entre les deux. Ces caractères ne sont pas des données mais des espaces, des tabulations, des retour chariots et certains caractères non visibles.

Pour éviter de traiter les données de ces événements, il y a plusieurs solutions :


Exemple :
import java.util.*;

/**
 * Classe utilisée pour gérer les événement émis par SAX lors du traitement du fichier XML
 */
public class TestXMLHandler extends org.xml.sax.HandlerBase {
  private String tagCourant = "";
  public TestXMLHandler() {
    super();
  }
  
  /**
   * Actions à réaliser sur les données
   */
  public void characters(char[] caracteres, int debut, int longueur) {
    String donnees = new String(caracteres, debut, longueur);
    if (!tagCourant.equals("") {
      System.out.println("  Element " + tagCourant 
        + ", valeur = *" + donnees + "*");
    }
  }
  
  /**
   * Actions à réaliser lors de la fin du document XML.
   */
  public void endDocument() {
    System.out.println("Fin du document");
  }
  
  /**
   * Actions à réaliser lors de la détection de la fin d'un élément.
   */
  public void endElement(String name) {
    tagCourant = "";
    System.out.println("Fin tag " + name);
  }
  
  /**
   * Actions à réaliser au début du document.
   */
  public void startDocument() {
    System.out.println("Debut du document");
  }
  
  /**
   * Actions a réaliser lors de la détection d'un nouvel élément.
   */
  public void startElement(String name, org.xml.sax.AttributeList atts) {
    tagCourant = name;
    System.out.println("debut tag : " + name);
  }
}
Résultat :
Lancement du parser
Debut du document
debut tag : BIBLIOTHEQUE
   Element BIBLIOTHEQUE, valeur = *
  *
debut tag : LIVRE
   Element LIVRE, valeur = *
    *
debut tag : TITRE
   Element TITRE, valeur = *titre livre 1*
Fin tag TITRE
debut tag : AUTEUR
   Element AUTEUR, valeur = *auteur 1*
Fin tag AUTEUR
debut tag : EDITEUR
   Element EDITEUR, valeur = *editeur 1*
Fin tag EDITEUR
Fin tag LIVRE
debut tag : LIVRE
   Element LIVRE, valeur = *
    *
debut tag : TITRE
   Element TITRE, valeur = *titre livre 2*
Fin tag TITRE
debut tag : AUTEUR
   Element AUTEUR, valeur = *auteur 2*
Fin tag AUTEUR
debut tag : EDITEUR
   Element EDITEUR, valeur = *editeur 2*
Fin tag EDITEUR
Fin tag LIVRE
debut tag : LIVRE
   Element LIVRE, valeur = *
    *
debut tag : TITRE
   Element TITRE, valeur = *titre livre 3*
Fin tag TITRE
debut tag : AUTEUR
   Element AUTEUR, valeur = *auteur 3*
Fin tag AUTEUR
debut tag : EDITEUR
   Element EDITEUR, valeur = *editeur 3*
Fin tag EDITEUR
Fin tag LIVRE
Fin tag BIBLIOTHEQUE
Fin du document

Exemple :
...
/**
 * Actions à réaliser sur les données
 */
public void characters(char[] caracteres, int debut, int longueur) {
	String donnees = new String(caracteres, debut, longueur);

	if (!tagCourant.equals("")) {	
		if(!Character.isISOControl(caracteres[debut])) {
    			System.out.println("   Element " + tagCourant 
                 +", valeur = *" + donnees + "*");
		}
	}
}		
...
Résultat :
Lancement du parser
Debut du document
debut tag : BIBLIOTHEQUE
debut tag : LIVRE
debut tag : TITRE
   Element TITRE, valeur = *titre livre 1*
Fin tag TITRE
debut tag : AUTEUR
   Element AUTEUR, valeur = *auteur 1*
Fin tag AUTEUR
debut tag : EDITEUR
   Element EDITEUR, valeur = *editeur 1*
Fin tag EDITEUR
Fin tag LIVRE
debut tag : LIVRE
debut tag : TITRE
   Element TITRE, valeur = *titre livre 2*
Fin tag TITRE
debut tag : AUTEUR
   Element AUTEUR, valeur = *auteur 2*
Fin tag AUTEUR
debut tag : EDITEUR
   Element EDITEUR, valeur = *editeur 2*
Fin tag EDITEUR
Fin tag LIVRE
debut tag : LIVRE
debut tag : TITRE
   Element TITRE, valeur = *titre livre 3*
Fin tag TITRE
debut tag : AUTEUR
   Element AUTEUR, valeur = *auteur 3*
Fin tag AUTEUR
debut tag : EDITEUR
   Element EDITEUR, valeur = *editeur 3*
Fin tag EDITEUR
Fin tag LIVRE
Fin tag BIBLIOTHEQUE
Fin du document

SAX définit une exception de type SAXParserException lorsque le parseur détecte une erreur dans le document en cours de traitement. Les méthodes getLineNumber() et getColumnNumber() permettent d'obtenir la ligne et la colonne où l'erreur a été détectée.

Exemple :
try {
...
}  catch (SAXParseException e) { 
  System.out.println("Erreur lors du traitement du document XML");
  System.out.println(e.getMessage());
  System.out.println("ligne : "+e.getLineNumber());
  System.out.println("colonne : "+e.getColumnNumber());
  }

Pour les autres erreurs, SAX définit l'exception SAXException.

 

42.2. L'utilisation de SAX de type 2

SAX de type 2 apporte principalement le support des espaces de noms. Les classes et les interfaces sont toujours définies dans les packages org.xml.sax et ses sous-packages.

SAX de type 2 définit quatre interfaces que l'objet handler doit ou peut implémenter :

Plusieurs classes et interfaces de SAX de type 1 sont deprecated :

 
ancienne entité SAX 1
nouvelle entité SAX 2
Interface
org.xml.sax.Parser
XMLReader
org.xml.sax.DocumentHandler
ContentHandler
org.xml.sax.AttributeList
Attributes
Classes
org.xml.sax.helpers.ParserFactory
 
org.xml.sax.HandlerBase
DefaultHandler
org.xml.sax.helpers.AttributeListImpl
AttributesImpl

Les principes de fonctionnement de SAX 2 sont très proches de SAX 1.

Exemple :
import org.xml.sax.*;
import org.xml.sax.helpers.*;

public class TestSAX2
{
  
  public static void main(String[] args)
  {
    try
    {
      Class c = Class.forName("org.apache.xerces.parsers.SAXParser");
      XMLReader reader = (XMLReader)c.newInstance();
      TestSAX2Handler handler = new TestSAX2Handler();
      reader.setContentHandler(handler);
      reader.parse("test.xml");
    }
    catch(Exception e){System.out.println(e);}
  }

}

class TestSAX2Handler extends DefaultHandler
{
  private String tagCourant = "";
  
  /**
   * Actions à réaliser lors de la détection d'un nouvel élément.
   */
  public void startElement(String nameSpace, String localName, 
    String qName, Attributes attr) throws SAXException  {
    tagCourant = localName;
    System.out.println("debut tag : " + localName);
  }

  /**
   * Actions à réaliser lors de la détection de la fin d'un élément.
   */
  public void endElement(String nameSpace, String localName, 
    String qName) throws SAXException {
    tagCourant = "";
    System.out.println("Fin tag " + localName);
  }

  /**
   * Actions à réaliser au début du document.
   */
  public void startDocument() {
    System.out.println("Debut du document");
  }

  /**
   * Actions à réaliser lors de la fin du document XML.
   */
  public void endDocument() {
    System.out.println("Fin du document");
  }

  /**
   * Actions à réaliser sur les données
   */
  public void characters(char[] caracteres, int debut, 
    int longueur) throws SAXException {
    String donnees = new String(caracteres, debut, longueur);

    if (!tagCourant.equals("")) {	
      if(!Character.isISOControl(caracteres[debut])) {
        System.out.println("   Element " + tagCourant +", 
          valeur = *" + donnees + "*");
      }
    }
  }
}

 

 


[ Précédent ] [ Sommaire ] [ Suivant ] [Télécharger ]      [Accueil ]

72 commentaires Donner une note à l'article (5)

 

Copyright (C) 1999-2016 Jean-Michel DOUDOUX. Vous pouvez copier, redistribuer et/ou modifier ce document selon les termes de la Licence de Documentation Libre GNU, Version 1.1 ou toute autre version ultérieure publiée par la Free Software Foundation; les Sections Invariantes étant constitués du chapitre Préambule, aucun Texte de Première de Couverture, et aucun Texte de Quatrième de Couverture. Une copie de la licence est incluse dans la section GNU FreeDocumentation Licence. La version la plus récente de cette licence est disponible à l'adresse : GNU Free Documentation Licence.

Responsables bénévoles de la rubrique Java : Mickael Baron - Robin56 -