Java & XML

SAX (Simple API for XML)

référence : http://www.saxproject.org.

Auteur : David Megginson.

Version : 2.0.1.

L'interface de programmation SAX propose une vision événementielle de l'analyse d'un document XML.

Principes de SAX

figures/java/sax.png

Objectifs :

L'analyse génère des évènements récupérés par SAX et passés à l'application.

Les packages Java de SAX 2

Les interfaces du package org.xml.sax:

ContentHandler     évènements liés au contenu
DTDHandler         évènements liés à la DTD
ErrorHandler       récupération des erreurs
Locator            récupération de la position
XMLReader          Analyseur
 | XMLFilter
AttributeList
Attributes
EntityResolver
...

Les classes du package org.xml.sax.helpers:

org.xml.sax.helpers.DefaultHandler
   implements org.xml.sax.ContentHandler,
   implements org.xml.sax.DTDHandler,
   implements org.xml.sax.EntityResolver,
   implements org.xml.sax.ErrorHandler
...

Premier programme SAX2

import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;

import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;

public class Essai extends DefaultHandler {

    public Essai () { super(); }

    public static void main (String args[]) throws Exception {
        // Analyseur Xerces par défaut (Java 5)
        XMLReader xr = XMLReaderFactory.createXMLReader();

        Essai handler = new Essai();
        xr.setContentHandler(handler);
        xr.setErrorHandler(handler);
        // xr.setDTDHandler(handler);
        xr.setFeature("http://xml.org/sax/features/validation", true);

        xr.parse(new InputSource(args[0]));
        }

Le gestionnaire de contenu

public void startDocument () {
    System.out.println("Start document");
    }

public void endDocument () {
    System.out.println("End document");
    }

public void startElement (
        String uri,
        String name,
        String qName,
        Attributes atts
        ) {
    System.out.println("Start element: {" + uri + "}" + name);
    }

public void endElement (String uri, String name, String qName) {
    System.out.println("End element:   {" + uri + "}" + name);
    }

Traiter les caractères

public void characters (char ch[], int start, int length) {
    System.out.print("Characters:     \"");
    for (int i = start; i < start + length; i++) {
        switch (ch[i]) {
            case '\\': System.out.print("\\\\"); break;
            case '"':  System.out.print("\\\""); break;
            case '\n': System.out.print("\\n"); break;
            case '\r': System.out.print("\\r"); break;
            case '\t': System.out.print("\\t"); break;
            default:   System.out.print(ch[i]); break;
            }
        }
    System.out.print("\"\n");
    }

Traiter les erreurs

public void error(SAXParseException e) {
    System.err.println("Erreur non fatale  (ligne " +
        e.getLineNumber() + ", col " +
        e.getColumnNumber() + ") : " + e.getMessage());
    }

public void fatalError(SAXParseException e) {
    System.err.println("Erreur fatale : " + e.getMessage());
    }

public void warning(SAXParseException e) {
    System.err.println("warning : " + e.getMessage());
    }

L'API DOM (Document Object Model)

figures/java/dom.png

♦ Représentation Objet en mémoire d'un document XML ou HTML (4.0).

♦ C'est une norme proposée par le consortium W3C (http://www.w3.org/DOM/) pour résoudre les problèmes liées au DHTML (HTML + CSS + JavaScript).

♦ Le DOM se compose de deux parties:

Le package Java org.w3c.dom

Les interfaces du package org.w3c.dom:

Node
 | Attr
 | CharacterData
 |  | Comment
 |  | Text
 |  |  | CDATASection
 | Document
 | DocumentFragment
 | DocumentType
 | Element
 | Entity
 | EntityReference
 | Notation
 | ProcessingInstruction

NamedNodeMap
NodeList

...

L'interface org.w3c.dom.Node

Les méthodes de l'interface org.w3c.dom.Node:

Node getFirstChild()         Node getNextSibling() 
Node getLastChild()          Node getPreviousSibling()
Node getParentNode()         NodeList getChildNodes() 
boolean hasChildNodes()      Document getOwnerDocument() 

NamedNodeMap getAttributes() 
boolean hasAttributes() 

String getLocalName()        String getNamespaceURI() 
String getNodeName()         String getPrefix() 

short getNodeType() 
String getNodeValue() 

Méthodes de modification :

Node appendChild(Node newChild) 
Node insertBefore(Node newChild, Node refChild) 
Node removeChild(Node oldChild) 
Node replaceChild(Node newChild, Node oldChild) 
void setNodeValue(String nodeValue) 
void setPrefix(String prefix)

Node cloneNode(boolean deep) 

... 

Premier programme DOM

Déclaration de l'analyseur XML et création du document:

import org.w3c.dom.*;
import java.io.*;

public class Exemple {

    public static void main(String[] args) throws Exception {
        Document doc;

        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setValidating(true);
    
        DocumentBuilder db = dbf.newDocumentBuilder();
    
        doc = db.parse(new File(args[0]));
        afficher("", doc);
        }
    
    ...

Parcours d'un arbre DOM

Parcours de l'arbre XML :

public static void afficher(String indent, Node n) {
    if (n.getNodeType() == org.w3c.dom.Node.TEXT_NODE) {
        System.out.println(indent + n.getNodeValue() );
        }
    else if (n instanceof Comment) {
        System.out.println(indent + "<!--" + n.getNodeValue() + " -->");
        }
    else if (n instanceof Element) {
        Element e = ((Element) n);
        System.out.println(indent + "<" + e.getTagName() + ">");
        NodeList fils = n.getChildNodes();
        for(int i=0; (i < fils.getLength()); i++) {
            afficher(indent + " | ", fils.item(i));
            }
        System.out.println(indent + "</" + e.getTagName() + ">");
        }
    else if (n instanceof Document) {
        NodeList fils = n.getChildNodes();
        for(int i=0; (i < fils.getLength()); i++) {
            afficher(indent, fils.item(i));
            }
        }
    }

JAXP (Java API for XML Processing)

figures/java/jaxp.png

proposé par JavaSoft (http://java.sun.com/xml/jaxp/) et présent depuis java2 version 1.4.

Unification des approches SAX & DOM

Proposition d'une API standard pour les transformations de documents XML (processeur XSL, FO et/ou XPATH).

Une usine à analyseurs

Le package javax.xml.parsers propose les classes

DocumentBuilderFactory     producteur d'analyseurs DOM
SAXParserFactory           producteur d'analyseurs SAX
DocumentBuilder            Analyseur DOM
SAXParser                  Analyseur SAX
...

Quelques méthodes de DocumentBuilderFactory :

static DocumentBuilderFactory  newInstance() 
                          ...  ...
                      boolean  isValidating() 
                         void  setValidating(boolean validating) 
                          ...  ...
              DocumentBuilder  newDocumentBuilder() 

Quelques méthodes de SAXParserFactory :

      static SAXParserFactory  newInstance() 
                          ...  ...
              DocumentBuilder  newDocumentBuilder() 
                    SAXParser  newSAXParser() 

Les analyseurs JAXP

Les usines servent à produire des analyseurs ayant certaines caractéristiques.

Quelques méthodes de DocumentBuilder:

Document  parse(java.io.File f)
Document  parse(org.xml.sax.InputSource is)
Document  parse(java.io.InputStream is)
Document  parse(java.lang.String uri)
     ...  ...
    void  setErrorHandler(org.xml.sax.ErrorHandler eh) 
     ...  ...

Quelques méthodes de SAXParser:

org.xml.sax.XMLReader  getXMLReader() 
                          ...  ...
void  parse(java.io.File        f,   DefaultHandler dh) 
void  parse(InputSource         is,  DefaultHandler dh) 
void  parse(java.io.InputStream is,  DefaultHandler dh) 
void  parse(java.lang.String    uri, DefaultHandler dh) 

Une usine pour transformer

Le package javax.xml.transform propose les classes

TransformerFactory  Fabrication des transformations
Transformer         Une transformation
OutputKeys          Le format de sortie d'une transformation

Quelques méthodes de TransformerFactory:

static TransformerFactory  newInstance() 
                      ...  ...
              Transformer  newTransformer() 
              Transformer  newTransformer(Source source) 
                      ...  ...
                Templates  newTemplates(Source source) 

Une Source peut être:

Les transformations

Quelques méthodes de Transformer:

void  setOutputProperty(String name, String value) 
void  setParameter(String name, java.lang.Object value)
 ...  ...
void  transform(Source xmlSource, Result outputTarget) 
 ...  ...

Un Result peut être:

Un exemple de transformation

Lecture, copie et sérialisation :

// Créer une usine à "transformer"
TransformerFactory factory = TransformerFactory.newInstance();

// Un premier "transformer" simple
Transformer analyseur = factory.newTransformer();

// Lire le document XML et en faire une copie
DOMResult xml = new DOMResult();
analyseur.transform(new StreamSource("test.xml"), xml);
DOMSource xmlSrc = new DOMSource(xml.getNode());
analyseur.transform(xmlSrc, new StreamResult("test2.xml") );

Utilisation d'une feuille de style XSLT :

// Un "transformer" processeur XSL
Transformer xslt = factory.newTransformer( new StreamSource("test.xsl") );

// appliquer la feuille XSLT
DOMResult out = new DOMResult();
xslt.transform(new DOMSource(xml.getNode()), out);

// Serialiser out dans "test.out" en iso-8859-1
analyseur.setOutputProperty(OutputKeys.INDENT, "yes");
analyseur.setOutputProperty(OutputKeys.ENCODING, "iso-8859-1");
analyseur.transform(
    new DOMSource(out.getNode()),
    new StreamResult("test.out")
    );

Les alternatives à SAX/DOM/JAXP

La librairie JDOM

Objectifs : offrir une bibliothèque simple pour la représentation et la manipulation de documents XML (http://www.jdom.org).

import org.jdom.Element;
import org.jdom.Document;
import org.jdom.output.XMLOutputter;

public static void main(String[] args)
    {
    Element stock = new Element("stock")
        .addContent(new Element("nom").setText("CD"))
        .addContent(new Element("prix").setText("100"));

    Document root = new Document(stock);
    XMLOutputter outputter = new XMLOutputter("  ",true,"iso-8859-1");
    
    try { outputter.output(root, System.out); }
    catch (java.io.IOException e) { }
    }

Des passerelles sont disponibles vers :

La librairie DOM4J

Une autre librairie qui utilise XPATH (http://www.dom4j.org).

import java.util.*;
import org.dom4j.Document;     import org.dom4j.DocumentHelper;
import org.dom4j.Element;

public class Dom4jSample {
    public static void main(String args[]) {
        Document document = DocumentHelper.createDocument();
        Element root = document.addElement( "root" );

        Element author2 = root.addElement( "author" )
            .addAttribute( "id", "Toby" ).addAttribute( "location", "Germany" )
            .addText( "Tobias Rademacher" );
        Element author1 = root.addElement( "author" )
            .addAttribute( "id", "James" ).addAttribute( "location", "UK" )
            .addText( "James Strachan" );

        List results = document.selectNodes("//author[@location = 'UK']");
        for ( Iterator iter = results.iterator(); iter.hasNext(); ) {
            Element element = (Element) iter.next();
            System.out.println(element.valueOf("concat(@id,' : ', .)"));
            }
        }
}

JAXB (Java API for XML Binding)

Objectif : mise en correspondance (binding) automatique entre une famille de documents XML et un schéma de classes Java.

Continuité entre :

Compilation d'un DTD/schéma

figures/jaxb/compil.png

à partir de la DTD suivante (et/ou du schéma) :

<!ELEMENT  personne  (nom,age,adresse)>
<!ELEMENT  nom       (#PCDATA)>
<!ELEMENT  age       (#PCDATA)>

<!ELEMENT  adresse   (rue,ville)>
<!ELEMENT  rue       (#PCDATA)>
<!ELEMENT  ville     (#PCDATA)>

nous obtenons

interface Personne {       |   interface Adresse {
   String  getNom();       |      String getRue();
   int     getAge();       |      String getVille();
   Adresse getAdresse();   |      }
   }                       |   

Lecture d'un fichier XML

figures/jaxb/unmarshal.png

En une seule opération le fichier XML peut être

Génération de documents XML

figures/jaxb/marshal.png

♦ Ce mécanisme est la base de la persistance d'objet implantée dans les EJB ou les JDO (Java data Object).

♦ Il existe d'autres framework de mise en correspondance XML-Java comme