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.


SommaireSAX (9)
précédent sommaire suivant
 

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.

Mis à jour le 4 décembre 2004 Ioan

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.

Mis à jour le 4 décembre 2004 Ioan

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()"); 
		} 
	} 
}
Ce code ne fait « rien », dans le sens que vous n'aurez aucun effet visible lors de son exécution. Cet exemple met juste en évidence l'obtention du parseur et les types d'exception susceptibles d'être levées. Pour un exemple d'implémentation de DefaultHandler, regardez : Comment parser un XML avec SAX ?

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 ?

Mis à jour le 4 décembre 2004 Ioan

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>
Voici un simple JavaBean Personne nous permettant de représenter une entrée dans cet 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(); 
	} 
}
Finalement, voici le DefaultHandler nous permettant le parsing du XML. Le parsing va simplement récupérer une List de Personne.

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); 
		} 
	} 
}
L'utilisation de ces trois éléments se fait simplement comme ceci :

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);
Il existe des API plus avancées que SAX pour lier des fichiers XML et des Object Java. L'exemple ci-dessus sert juste de démonstration.

Mis à jour le 4 décembre 2004 Ioan

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; 
}
Pour un exemple d'utilisation, téléchargez le fichier ci-dessous.

Mis à jour le 4 décembre 2004 Ioan

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(); 
		}  
 	} 
}

Mis à jour le 3 septembre 2014 Robin56

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();

Mis à jour le 1er septembre 2014 Robin56

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.

Mis à jour le 3 septembre 2014 Robin56

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.

Mis à jour le 4 décembre 2004 Ioan

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 ça


Réponse à la question

Liens sous la question
précédent sommaire suivant
 

Les 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 © 2017 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.

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