Lire un fichier XML via l'API SAX en JAVA

Afficher des informations sur un fichier XML

XML Parser

Dans cet exercice, on va parcourir un fichier XML et puis afficher dans la console les différentes informations présentes dans ce fichier.

L'affichage dans la console doit ressembler à l'exemple ci-dessous.

1
Debut de l'analyse du document
2
Ouverture de la balise : [Nom de la balise]
3
--------- Traitement du namespace : [URI du Namespace] dont le prefix est : [Prefix] --------
4
Ouverture de la balise : [Nom de la balise ]
5
appartenant au namespace : [URI du namespace]
6
Attributs :
7
- Attribut [Clée de l'attribut] = [Valeur de l'attribut ]
8
--------------------- Fin de traitement du namespace : [Prefix] ------------------
9
Fermeture de la balise : [Nom de la balise]
10
Fin de l'analyse du document
11

Question

Téléchargez cette archive contenant une version incomplète de la solution, puis ouvrez la avec Eclipse.

Vous trouverez les fichiers nécessaires dans le dossier Ressource.

ExerciceSAX.zip

Question

Remplissez les interfaces nécessaires pour avoir l'affichage souhaité dans la console.

Indice

Pour les attributs, utilisez les méthodes getLocalName() et getValue() de l'instance attributs.

Indice

Pour la gestion des namespace, vous pouvez utiliser la feature qui est dédié pour cela.

1
reader.setFeature("http://xml.org/sax/features/namespaces", true);
2
reader.setFeature("http://xml.org/sax/features/namespace-prefixes",true);
Indice

Assurez vous que la feature validation est activée.

1
reader.setFeature("http://xml.org/sax/features/validation", true);
Indice

Il faut aussi implémenter l'interface ErrorHandler pour afficher toutes les types d'erreur possible.

Solution

ContentHandler

1
public class myContentHandler implements ContentHandler {
2
3
private Locator locator;
4
    
5
    public myContentHandler()
6
    {
7
        super();
8
        locator  = new LocatorImpl();
9
    }
10
    
11
    /**
12
     * Definir le locator.
13
     */
14
    @Override
15
    public void setDocumentLocator(Locator value) {
16
        locator= value;
17
    }
18
    
19
    /**
20
     * Evenement recu au debut de l'analyse du document XML
21
     */
22
    @Override
23
    public void startDocument() throws SAXException {
24
        System.out.println("Debut de l'analyse du document");
25
    }
26
27
    /**
28
     * Evenement recu a la fin de l'analyse du document XML
29
     */
30
    @Override
31
    public void endDocument() throws SAXException {
32
        System.out.println("Fin de l'analyse du document" );
33
    }
34
    
35
    /**
36
     * Evenement recu au debut du mapping sur un namespace
37
     * @param prefix le nom du préfixe choisi.
38
     * @param URI le lien du namespace
39
     */
40
41
    @Override
42
    public void startPrefixMapping(String prefix, String URI) throws SAXException {
43
    	System.out.print("-----------------------------  ");
44
        System.out.print("Traitement du namespace : " + URI + " dont le prefix est : " + prefix);
45
        System.out.println("  -----------------------------");
46
    }
47
48
    /**
49
     * Evenement recu a la fin du mapping sur un namespace
50
     * @param prefix le nom du préfixe choisi.
51
     */
52
    @Override
53
    public void endPrefixMapping(String prefix) throws SAXException {
54
    	System.out.print("---------------------  ");
55
        System.out.print("Fin de traitement du namespace : " + prefix);
56
        System.out.println("  ------------------");
57
    }
58
    
59
    /**
60
    * Evenement recu a chaque fois que l'analyseur rencontre une balise XML ouvrante.
61
    * @param nameSpaceURI l'URL de l'espace de nommage.
62
    * @param localName le nom local de la balise.
63
    * @param rawName nom de la balise en version 1.0 <code>nameSpaceURI + ":" + localName</code>
64
    */
65
66
    @Override
67
    public void startElement(String nameSpaceURI, String localName, String rawName, Attributes attributs) throws SAXException {
68
69
        System.out.println("Ouverture de la balise : " + localName);
70
        
71
        if ( ! "".equals(nameSpaceURI)) {
72
                System.out.println("  appartenant au namespace : " + nameSpaceURI);
73
        }
74
        if(attributs.getLength()!=0)
75
        	System.out.println("  Attributs : ");
76
        
77
        for (int index = 0; index < attributs.getLength(); index++) { 
78
                System.out.println("     - Attribut "+ (index+1) +  attributs.getLocalName(index) + " = " + attributs.getValue(index));
79
        }
80
    }
81
82
    /**
83
     * Evenement recu a chaque fois que l'analyseur rencontre une balise XML ouvrante.
84
     * @param nameSpaceURI l'URL de l'espace de nommage.
85
     * @param localName le nom local de la balise.
86
     * @param rawName nom de la balise en version 1.0 <code>nameSpaceURI + ":" + localName</code>
87
     */
88
    @Override
89
    public void endElement(String nameSpaceURI, String localName, String rawName) throws SAXException {
90
91
        System.out.print("Fermeture de la balise : " + localName);
92
        if ( ! "".equals(nameSpaceURI)) { // name space non null
93
                System.out.print(" appartenant a l'espace de nommage : " + localName);
94
        }
95
        System.out.println();
96
    }
97
98
    /**
99
      * @param ch les caracteres qui sont dans un élément.
100
      * @param start le rang du premier caractere a traiter .
101
      * @param length la taille de la chaine a traiter.
102
      */
103
    @Override
104
    public void characters(char[] ch, int start, int length) throws SAXException {
105
    		System.out.println("Texte : " + new String(ch, start, length));
106
    }
107
108
    @Override
109
    public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
110
    	System.out.println("Espace inutile : " + new String(ch, start, length));
111
    }
112
113
    @Override
114
    public void processingInstruction(String target, String data) throws SAXException {
115
    	throw new UnsupportedOperationException("Not supported yet."); 
116
    }
117
118
    @Override
119
    public void skippedEntity(String string) throws SAXException {
120
        throw new UnsupportedOperationException("Not supported yet."); 
121
    }
122
123
}

ComplémentErrorHandler

1
public class myErrorHandler implements ErrorHandler{
2
3
	@Override
4
    public void warning(SAXParseException SaxException) throws SAXException {
5
        System.out.println("Warning : "+SaxException.getMessage());
6
    }
7
8
    @Override
9
    public void error(SAXParseException SaxException) throws SAXException {
10
        System.out.println("Non fatal error : "+SaxException.getMessage());
11
    }
12
13
    @Override
14
    public void fatalError(SAXParseException SaxException) throws SAXException {
15
        System.out.println("Fatal error : "+SaxException.getMessage());
16
    }
17
18
}

ComplémentmySAXReader

1
public mySAXReader(String uri) throws SAXException, IOException, ParserConfigurationException 
2
    {
3
        XMLReader reader = XMLReaderFactory.createXMLReader("org.apache.xerces.parsers.SAXParser");
4
5
        reader.setFeature("http://xml.org/sax/features/validation", true);
6
        reader.setFeature("http://xml.org/sax/features/namespaces", true);
7
        reader.setFeature("http://xml.org/sax/features/namespace-prefixes",true);
8
        reader.setContentHandler(new myContentHandler());
9
        reader.setErrorHandler(new myErrorHandler());
10
        
11
        reader.parse(new InputSource(uri));
12
    }

Question

Dans cette question, vous serez invitées à garder vos Handler déjà faits pour la question précédente.

On va analyser de la même façon un autre fichier XML. Pour cela, vous allez ouvrir le fichier file2.xml dans votre fonction main.

L'analyse se traite bien ? Si non, expliquez pourquoi et trouvez une solution sans modifié le fichier file2.xml.

Indice

Utilisez les EntityResolver pour changer la DTD utilisé.

Solution

FondamentalExplication

Le problème provient du fichier DTD qui est référencé dans le XML. En effet, le XML rajoute une balise qui n'est pas déclarée dans la DTD.

Pour résoudre ce problème, on peut utiliser un autre fichier DTD qui est plus conforme avec le XML. Pour cela on doit utiliser l'interface EntityResolver.

Le code source à introduire :

Dans la classe mySAXReader :

1
reader.setFeature("http://xml.org/sax/features/validation", true);
2
reader.setEntityResolver(new myEntityResolver());

Dans la classe myEntityResolver 

1
@Override
2
    public InputSource resolveEntity(String publicID, String systemID) throws SAXException, IOException {
3
		
4
        System.out.println("Resolve entity : public ID : "+publicID+" SystemID : "+systemID);
5
        return new InputSource("fileCorrect.dtd");
6
    }
7

Complément

Cela reste un cas très simple et basique.

Souvent cette classe est utile quand on a des références avec des PublicID, et qu'on souhaite au lieu de ça utiliser des ressources local avec SystemID.

Exemple : on référence un schéma qui est publié sur internet, mais on n'a pas accès à internet, donc on souhaite utilisez un schéma local. Dans ce cas on appelle la classe EntityResolver qui envoie le bon fichier à utiliser.

Solution

La solution complète :

Téléchargez cette archive contenant une version complète de la solution

SolutionExerciceSAX.zip

PrécédentPrécédentFin
AccueilAccueilImprimerImprimer Mourad SAADI, 2015 (Contributions : Stéphane Crozat, les étudiants de NF29) Paternité - Partage des Conditions Initiales à l'IdentiqueRéalisé avec Scenari (nouvelle fenêtre)