P
'
t
i
t
e
C
h
a
t
t
e
 
spacer~ OUT OF MY MIND. BACK IN FIVE MINUTES. Articles | Connexion
 
~Java et SAX

Précédent  
  XML-XSLT  
  Suivant
 Présentation

Deux API se partagent le domaine de la gestion de documents XML. L'une et l'autre possèdent des objectifs et des moyens différents. Nous allons étudier l'une d'entre elles, la Simple API for XML.
 Sommaire


 Introduction

Pour illustrer l'utilisation de SAX au cour d'une application Java, nous allons régider un lecteur de propriétés. Un jeu de propriété constitue un ensemble de paires de données : à chaque clé se voit associée une valeur. Il s'agit d'une représentation textuelle des objets Hashtable et HashMap de la librairie Java 2. Les jeux de propriétés s'emploient souvent pour lire et enregistrer des configurations logicielles.

La première étape de notre périple réside dans la rédaction d'une DTD pour définir la structure des documents que nous serons amenés à manipuler. Nous savons que chaque propriété doit posséder deux attributs : un nom et une valeur. Pour le nom, tous les avis convergent et le définissent en tant qu'attribut d'une balise <property>. Toutefois, une alternative ressort alors que l'on se penche sur le cas de la valeur. Le premier terme de l'alternative énonce que la valeur doit-elle aussi se voir définie en tant qu'attribut d'élément. L'autre terme prévoit que la valeur doit s'écrire comme un noud texte interne à la balise.

Nous avons au final le choix entre ces deux méthodes :

<property name="isaac" valeur="asimov" />
<property name="fredric">brown</property>
       
      
JextCopier dans Jext | Jext | Plugin Codegeek
Certes, ces considérations peuvent apparaître comme relevant d'une futilité exacerbée. Néanmoins, la difficulté du choix occasionné par de telles situations, attribut contre noud texte voir élément fils, constitue un problème récurrent en XML et il s'avère indispensable de s'y sensibiliser.


 Les angles aux SAX ont beau jeu

La solution retenue pour notre projet correspond à l'emploi d'un unique attribut de clé. Ceci nous donnera l'occasion de découvrir un peu mieux SAX. Pour parvenir à nos fins nous allons faire appel aux services de la version 2.2 de l'efficace Xerces d'IBM. Outre la richesse de son API et son support de DOM et SAX, Xerces possède l'aptitude de valider les documents XML. La détection d'erreurs s'en voit grandement simplifiée.

La manipulation d'un document XML par l'entremise de l'API SAX nécessite l'emploi de deux packages : org.xml.sax, qui contient les interfaces de manipulation, et javax.xml.parsers, qui contient les "fabriques" de parser. A ceux-ci peut se voir adjoindre org.xml.sax.helpers qui offre des implémentations vides des interfaces de manipulation.

Les impleméntations de l'API SAX laissent loisir au programmeur d'employer trois gestionnaires disctincts : le DocumentHandler, l'ErrorHandler et le DTDHandler. Le plus fréquemment employé reste le premier et nous nous cantonnerons à celui-ci. L'interface org.xml.sax.DocumentHandler recèle onze méthodes à implémenter. La liste exhaustive des ces dernières est récapitulée dans l'encadré numéro un. Les noms des méthodes s'avèrent très explicites.

Note 1
  • void characters(char[] ch, int start, int length)
  • void endDocument()
  • void endElement(String namespaceURI, String localName, String qName)
  • void endPrefixMapping(String prefix)
  • void ignorableWhitespace(char[] ch, int start, int length)
  • void processingInstruction(String target, String data)
  • void setDocumentLocator(Locator locator)
  • void skippedEntity(String name)
  • void startDocument()
  • void startElement(String namespaceURI, String localName,
    String qName, Attributes atts)
  • void startPrefixMapping(String prefix, String uri)


 Le dindon de la parse

Avant de songer à employer une implementation de DocumentHandler, nous devons nous soucier d'avoir un parser à notre disposition. L'obtention d'un parser passe par la classe SAXParserFactory. Nous devons en premier lieu générer une "fabrique SAX" :

SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setValidating(true);
       
      
JextCopier dans Jext | Jext | Plugin Codegeek
La seconde ligne active le mode validant du parser. Nanti de notre nouvelle fabrique, nous pouvons alors créer le parser proprement dit :

SAXParser parser = factory.newSAXParser();
PropertiesHandler handler = new PropertiesHandler();
       
      
JextCopier dans Jext
L'instance de PropertiesHandler générée se reporte à une classe interne héritant des propriétés de l'interface DocumentHandler. Notez que la création d'un parser SAX peut lever une exception de type ParserConfigurationException ou une exception SAXException. Le début de l'opération de "parsing" proprement dite est marqué par l'invocation de la méthode parse() de la classe SAXParser.

Cette méthode prend deux arguments en paramètre, soit une source de données et un gestionnaire DefaultHandler. La source de données peut être représentée par un fichier, un flux de lecture (InputStream), ou un URI. Notre exemple emploie un fichier.

parser.parse(new File(path), handler);
       
      
JextCopier dans Jext
Au cours de l'opétation, des exceptions IOException ou SAXException peuvent apparaître.


 Des fautes en dehors

La classe nous servant de gestionnaire SAX hérite de la classe org.xml.sax.DefaultHandler. Celle-ci constitue une classe implémentant les gestionnaires de document, de DTD et d'erreur. Aucune implémentation de leurs méthodes n'est proposée, mais elle évite au développeur de rédiger l'intégraliter des signatures des méthodes du gestionnaire. Parmi les diverses méthodes à notre disposition, trois nous intéressent : startDocument(), startElement() et characters(). La première nous permet d'initialiser les objets requis par le processus. Cette méthode est invoquée lorsque le processus de lecture du document commence. La seconde méthode correspond à la rencontre d'une balise dans le document. Sa cousine endElement() notifie la fin d'une balise. Enfin character() sert à traiter le flot de texte compris entre une balise ouvrante et une balise fermante. Le listing suivant reporte le contenu de la classe PropertiesHandler.

class PropertiesHandler extends DefaultHandler
{
  private HashMap properties = null;
  private String propertyKey = null;

  public void characters(char[] ch, int start, int length)
  {
    if (propertyKey != null)
      properties.put(propertyKey, new String(ch, start, length));
  }

  public void startDocument()
  {
    properties = new HashMap();
  }

  public void startElement(String uri, String localName,
   String qName, Attributes attributes)
  {
    if (qName.equalsIgnoreCase("property"))
    {
      String value = attributes.getValue("name");
      if (value != null)
      {
        propertyKey = value;
        return;
      }
    }

    propertyKey = null;
  }

  public HashMap getProperties()
  {
    return properties;
  }
}
       
      
JextCopier dans Jext | Jext | Plugin Codegeek
Lorsqu'une balise <property> s'ouvre, notre gestionnaire retient la valeur de l'attribut "name". Puis, lorsque qu'un flot de caractères émerge, le gestionnaire place la chaîne correspondant au flot dans une table de hachage de type HashMap. La clé liée au texte correspond à la variable propertyKey, contenant la valeur de l'attribut "name".

SAX se révèle particulièrement adapté à une telle application de XML. Le code contenu dans notre gestionnaire se veut concis et simple. La réalisation d'une même application à l'aide de DOM exigerait de nombreuses lignes de code supplémentaires. En outre, la lecture d'un tel code s'avérerait bien moins naturelle.


 Téléchargement

Vous pouvez télécharger le code source d'exemple de cet article. Il contient en outre les librairies nécessaires ainsi que des fichiers d'exemple.



par Romain Guy
romain.guy@jext.org
http://www.jext.org
Dernière mise à jour : 14/10/2006


Précédent  
  XML-XSLT  
  Suivant

 
#ProgX©2005 Mathieu GINOD - Romain GUY - Erik LOUISE