FAQ Java XMLConsultez toutes les FAQ
Nombre d'auteurs : 5, nombre de questions : 59, dernière mise à jour : 3 septembre 2014 Ajouter une question
Cette FAQ a été réalisée à partir des questions fréquemment posées sur les forums de http://www.developpez.com et de l'expérience personnelle des auteurs.
Nous tenons à souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle propose sont correctes. Les auteurs font leur maximum, mais l'erreur est humaine. Cette FAQ ne prétend pas non plus être complète. Si vous trouvez une erreur, ou que vous souhaitez nous aider en devenant rédacteur, lisez ceci.
- Comment fonctionne l'API SAX ?
- Doit-on implémenter les quatre types de handlers ?
- Comment créer un parseur avec SAX ?
- Comment parser un XML avec SAX ?
- Comment gérer les erreurs durant le parsing ?
- Comment vérifier le DTD d'un fichier XML avec SAX ?
- Comment ignorer la vérification DTD avec SAXBuilder ?
- En lisant de gros fichiers avec le parser SAX, j'obtiens une OutOfMemoryException, que faire ?
- Où trouver plus d'informations sur SAX ?
Architecture d'une application utilisant SAX :
Pour commencer, l'application récupère un parseur (javax.xml.parsers.SAXParser) à partir d'une fabrique de parseurs (javax.xml.parsers.SAXParserFactory).
Ce parseur parcourt le document XML grâce à un lecteur (org.xml.sax.XMLReader). Ce dernier contient plusieurs gestionnaires (ou handlers). Ce sont ces différents gestionnaires qui sont chargés du traitement des « événements » lors du parsing. Voici les quatre principaux types de handlers (interfaces du package org.xml.sax) :
- Gestionnaire de Contenu : le ContentHandler est chargé des événements comme le début ou la fin du document, l'ouverture ou a fermeture de balises ou encore la lecture de caractères ;
- Gestionnaire d'Erreurs : le ErrorHandler va traiter les trois types d'erreurs possibles lors du parsing : les erreurs simples, les erreurs fatales et les warnings ;
- Gestionnaire de DTD : le DTDHandler (Document Type Definition) gère les événements relatifs aux DTD ;
- Gestionnaire d'entités externes : l'EntityResolver est chargé de gérer les entités externes, en fournissant une InputSource adéquate.
Non, ce n'est pas nécessaire. Il faut utiliser la classe DefaultHandler du package org.xml.sax.helpers.
Le fonctionnement de cette classe peut être comparé à celui des adapters pour les listeners (AWT et Swing). C'est-à-dire que cette classe propose une implémentation par défaut des quatre types de gestionnaires.
Vous avez simplement besoin d'étendre cette classe afin d'implémenter les méthodes qui vous sont utiles. Pour un exemple, regardez : Comment parser un XML avec SAX ?
Vous pouvez aussi regarder du côté de la classe org.xml.sax.ext.DefaultHandler2, qui propose en plus des quatre handlers de base une implémentation par défaut de DeclHandler, EntityResolver2 et LexicalHandler. Ces trois gestionnaires sont des extensions pour SAX2.
Voici un exemple de création de parseur SAX utilisant un DefaultHandler.
Code java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | import org.xml.sax.*; import org.xml.sax.helpers.*; import javax.xml.parsers.*; import java.io.*; public class ExempleSAX { public static void main(String[] args){ try{ // création d'une fabrique de parseurs SAX SAXParserFactory fabrique = SAXParserFactory.newInstance(); // création d'un parseur SAX SAXParser parseur = fabrique.newSAXParser(); // lecture d'un fichier XML avec un DefaultHandler File fichier = new File("./ExempleSAX.xml"); DefaultHandler gestionnaire = new DefaultHandler(); parseur.parse(fichier, gestionnaire); }catch(ParserConfigurationException pce){ System.out.println("Erreur de configuration du parseur"); System.out.println("Lors de l'appel à newSAXParser()"); }catch(SAXException se){ System.out.println("Erreur de parsing"); System.out.println("Lors de l'appel à parse()"); }catch(IOException ioe){ System.out.println("Erreur d'entrée/sortie"); System.out.println("Lors de l'appel à parse()"); } } } |
Voici quelques propriétés du parseur (SAXParser) que vous pouvez spécifier à la fabrique (SAXParserFactory) :
- setValidating(boolean) : indique si les parseurs produits par la fabrique doivent valider la DTD. Par défaut, cette valeur est false ;
- setSchema(Schema) : indique que les parseurs produits par la fabrique doivent valider le document XML selon un schéma XML W3C ;
- setFeature(String, boolean) : permet d'indiquer une propriété particulière pour les parseurs produits par la fabrique. Pour une liste de ces propriétés, regardez le lien ci-dessous ;
- setNamespaceAware(boolean) : indique si les parseurs produits par la fabrique supportent les espaces de nommage XML.
Pour finir, vous pouvez configurer encore plus profondément votre parseur avec la méthode setProperty(String, Object) de la classe SAXParser.
Pour une liste des features et properties, vous pouvez regarder la description du package org.xml.sax.
Pour un exemple simple (affichage sur la sortie standard du XML), téléchargez le fichier ci-dessous.
Pour un exemple plus complet, regardez : Comment parser un XML avec SAX ?
Imaginons le fichier XML suivant, qui représente un « annuaire » :
Code xml : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 | <annuaire> <personne id="0"> <nom>nom0</nom> <prenom>prenom0</prenom> <adresse>adresse0</adresse> </personne> <personne id="1"> <nom>nom1</nom> <prenom>prenom1</prenom> <adresse>adresse1</adresse> </personne> </annuaire> |
Code java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | public class Personne{ private int id; private String nom, prenom, adresse; public Personne(){} public int getId(){return id;} public String getNom(){return nom;} public String getPrenom(){return prenom;} public String getAdresse(){return adresse;} public void setId(int id){this.id = id;} public void setNom(String nom){this.nom = nom;} public void setPrenom(String prenom){this.prenom = prenom;} public void setAdresse(String adresse){this.adresse = adresse;} public String toString(){ return new StringBuffer("Nom : ").append(nom).append(", ") .append("Prenom : ").append(prenom).append(", ") .append("Adresse : ").append(adresse) .toString(); } } |
Code java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | public class PersonneHandler extends DefaultHandler{ //résultats de notre parsing private List<Personne> annuaire; private Personne personne; //flags nous indiquant la position du parseur private boolean inAnnuaire, inPersonne, inNom, inPrenom, inAdresse; //buffer nous permettant de récupérer les données private StringBuffer buffer; // simple constructeur public PersonneHandler(){ super(); } //détection d'ouverture de balise public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException{ if(qName.equals("annuaire")){ annuaire = new LinkedList<Personne>(); inAnnuaire = true; }else if(qName.equals("personne")){ personne = new Personne(); try{ int id = Integer.parseInt(attributes.getValue("id")); personne.setId(id); }catch(Exception e){ //erreur, le contenu de id n'est pas un entier throw new SAXException(e); } inPersonne = true; }else { buffer = new StringBuffer(); if(qName.equals("nom")){ inNom = true; }else if(qName.equals("prenom")){ inPrenom = true; }else if(qName.equals("adresse")){ inAdresse = true; }else{ //erreur, on peut lever une exception throw new SAXException("Balise "+qName+" inconnue."); } } } //détection fin de balise public void endElement(String uri, String localName, String qName) throws SAXException{ if(qName.equals("annuaire")){ inAnnuaire = false; }else if(qName.equals("personne")){ annuaire.add(personne); personne = null; inPersonne = false; }else if(qName.equals("nom")){ personne.setNom(buffer.toString()); buffer = null; inNom = false; }else if(qName.equals("prenom")){ personne.setPrenom(buffer.toString()); buffer = null; inPrenom = false; }else if(qName.equals("adresse")){ personne.setAdresse(buffer.toString()); buffer = null; inAdresse = false; }else{ //erreur, on peut lever une exception throw new SAXException("Balise "+qName+" inconnue."); } } //détection de caractères public void characters(char[] ch,int start, int length) throws SAXException{ String lecture = new String(ch,start,length); if(buffer != null) buffer.append(lecture); } //début du parsing public void startDocument() throws SAXException { System.out.println("Début du parsing"); } //fin du parsing public void endDocument() throws SAXException { System.out.println("Fin du parsing"); System.out.println("Resultats du parsing"); for(Personne p : annuaire){ System.out.println(p); } } } |
Code java : | Sélectionner tout |
1 2 3 4 5 6 | SAXParserFactory fabrique = SAXParserFactory.newInstance(); SAXParser parseur = fabrique.newSAXParser(); File fichier = new File("./ExempleSAX.xml"); DefaultHandler gestionnaire = new PersonneHandler(); parseur.parse(fichier, gestionnaire); |
Au niveau du document XML, il existe deux types d'erreurs possibles.
- Le document peut être non valide. Dans ce cas, le document n'obéit pas à la DTD ou au schéma qu'on lui a imposé.
- Le document peut être mal formé. Dans ce cas, il y a simplement une erreur par rapport au standard XML lui-même. Par exemple, des balises mal fermées ou se chevauchant.
Par contre, au niveau du parseur SAX, il existe trois niveaux d'erreurs. Ces trois niveaux d'erreurs sont représentées au niveau du Gestionnaire d'Erreurs (ErrorHandler) :
- Erreur fatale (fatalError(SAXParseException exception) throws SAXException) : cette erreur ne peut être récupérée. C'est le cas par exemple pour un document mal formé. Après ce type d'erreur, le parseur SAX arrête son travail.
- Erreur (error(SAXParseException exception) throws SAXException) : cette erreur peut être récupérée, c'est-à-dire que le parseur SAX peut continuer à traiter le reste du document XML. Ce genre d'erreur peut se produire lors d'une violation d'une contrainte imposée par la DTD ou le schéma.
- Warning (warning(SAXParseException exception) throws SAXException) : c'est un simple avertissement. Après cela, le parseur SAX continue le parsing du document.
Pour plus d'information sur ces erreurs, vous pouvez regarder XML 1.0 W3C Recommendation. Par défaut (cf. DefautHandler), seules les erreurs fatales sont « traitées ».
Voici un exemple d'implémentation de ErrorHandler. Cet exemple détaille sur la sortie standard les erreurs simples et warnings et lève une SAXException pour les erreurs fatales :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | protected String message(SAXParseException e){ String message = "Message : "+e.getMessage()+"\n"; message += "Ligne "+e.getLineNumber()+", colonne "+e.getColumnNumber()+"\n"; message += "Public id : "+e.getPublicId()+"\n"; message += "System id : "+e.getSystemId(); return message; } protected void printSAXException(SAXParseException e){ System.out.println(message(e)); if(e.getException() != null){ e.getException().printStackTrace(); } } public void warning(SAXParseException exception) throws SAXException{ System.out.println("*** Warning ***"); printSAXException(exception); } public void error(SAXParseException exception) throws SAXException{ System.out.println("*** Erreur ***"); printSAXException(exception); } public void fatalError(SAXParseException exception) throws SAXException{ String message = "*** Erreur fatale ***\n"; message += message(exception); SAXException se = new SAXException(message, exception); throw se; } |
Il faut implémenter l'interface DTDHandler dans son Handler puis activer la validation avec factory.setValidating(true).
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | public class Handler extends DefaultHandler implements DTDHandler{ public void endDocument() throws SAXException { System.out.println("Fin du document"); } public void endElement(String uri, String localName, String qName) throws SAXException { System.out.println("Fin de l'élément " + qName); } public void startDocument() throws SAXException { System.out.println("Début du document"); } public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { System.out.println("Début de l'élément " + qName); } public static void main(String[] args){ try{ // instanciation d'une fabrique de parseurs SAX SAXParserFactory factory = SAXParserFactory.newInstance(); // instanciation d'un parseur SAX SAXParser parser = factory.newSAXParser(); // activation de la validation XML factory.setValidating(true); DefaultHandler handler = new Handler(); // lecture d'un fichier XML parser.parse("test.xml", handler); } catch(Exception e){ System.err.println(e.getMessage()); e.printStackTrace(); } } } |
Si vous ne disposez pas des fichiers DTD, il est néanmoins possible d'ignorer la vérification DTD avec SAX.
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 | SAXBuilder saxBuilder = new SAXBuilder(false); saxBuilder.setValidation(false); saxBuilder.setFeature("http://xml.org/sax/features/validation", false); saxBuilder.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false); saxBuilder.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); Document document = saxBuilder.build(destFile); Element root = document.getRootElement(); |
En lisant de gros fichiers avec le parser SAX standard fourni dans le JDK, il est possible d'avoir une exception OutOfMemoryException. C'est un bug lié à l'implémentation par défaut de SAX fournie par SUN. Ce problème apparaît avec le JDK6 pour des update inférieurs à 14.
Il est donc conseillé de fournir soi-même les JARs d'une autre implémentation tels que WoodStox ou Apache Xerces.
Note : si vous utilisez Xerces et Tomcat, il se peut que vous ayez des ClassCastException au chargement de votre application. Ceux-ci sont dus à priori à un conflit entre l'implémentation utilisée par Tomcat et celles que vous fournissez. Dans ce cas, utilisez WoodStox.
Pour de plus amples informations sur SAX, vous pouvez regarder l'excellent tutoriel de Sébatien Méric : Lecture d'un flux XML via SAX.
Vous pouvez avoir d'autres informations sur l'utilisation de SAX, en anglais cette fois-ci, dans le J2EE 1.4 Tutorial.
Proposer une nouvelle réponse sur la FAQ
Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour çaLes sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2024 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.