import org.w3c.dom.Document;
//
// Éléments pour l'interface personne/ machine
//
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.JSplitPane;
import javax.swing.JEditorPane;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.WindowEvent;
import java.awt.event.WindowAdapter;
//
// Éléments pour l'arbre et son modèle
//
import javax.swing.tree.*;
import javax.swing.event.*;
import java.util.*;
//
// Notre petite classe
//
public class AfficheurDOM extends ConsommateurDOM {
public static void main (String [] args) {
if (args.length == 0) {
System.err.println ("Usage: java AfficheurDOM fichierXML [fichierXML ...]");
} else {
for (String s : args) {
AfficheurDOM ad = new AfficheurDOM ();
ad.consommer (s);
}
}
}
//
// Le traitement du document à proprement dit
//
protected void traiter (Document doc) {
Affichage aff = new Affichage (doc);
aff.init ();
aff.addWindowListener (
new WindowAdapter () {
public void windowClosing (WindowEvent we) {
System.exit (0);
}
}
);
aff.pack();
aff.setVisible (true);
}
private class Affichage extends JFrame {
Document m_Document;
public Affichage (Document doc) {
super ("Affichage d'un document XML avec DOM");
m_Document = doc;
}
public void init () {
final int HAUTEUR = 460;
final int LARGEUR_GAUCHE = 300;
final int LARGEUR_DROITE = 340;
final int LARGEUR_TOTALE = LARGEUR_GAUCHE + LARGEUR_DROITE;
final int ÉPAISSEUR_BORDURE = 5;
final int ESPACEMENT = ÉPAISSEUR_BORDURE * 2;
//
// Nous allons afficher le document dans un arbre
// (c'est assez naturel comme représentation)
//
JTree Arborescence = new JTree(new AdaptateurDOMTreeModel(m_Document));
//
// Côté gauche...
//
JScrollPane vueEnArbre = new JScrollPane(Arborescence);
vueEnArbre.setPreferredSize
(new Dimension (LARGEUR_GAUCHE, LARGEUR_TOTALE));
//
// Côté droit...
//
JEditorPane panneauHTML = new JEditorPane("text/html","");
panneauHTML.setEditable(false);
JScrollPane vueHTML = new JScrollPane(panneauHTML);
vueHTML.setPreferredSize
(new Dimension(LARGEUR_DROITE, LARGEUR_TOTALE));
//
// Vue séparée en deux...
//
JSplitPane panneauSéparé =
new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, vueEnArbre, vueHTML);
panneauSéparé.setContinuousLayout( true );
panneauSéparé.setDividerLocation( LARGEUR_GAUCHE );
panneauSéparé.setPreferredSize
(new Dimension(LARGEUR_TOTALE + ESPACEMENT, LARGEUR_TOTALE + ESPACEMENT));
setLayout(new BorderLayout());
add(panneauSéparé, BorderLayout.CENTER);
}
}
//
// Tableau contenant les noms des types de noeuds DOM. Les indices
// correspondent aux valeurs des types dans org.w3c.dom.Node, plus bas
//
private static final String[] NOMS_TYPES_NOEUDS = {
"none",
"Element",
"Attr",
"Text",
"CDATA",
"EntityRef",
"Entity",
"ProcInstr",
"Comment",
"Document",
"DocType",
"DocFragment",
"Notation"
};
//
// Enrobe un noeud DOM en donnant accès au texte à afficher dans
// l'arbre. Donne aussi accès aux enfants et aux indices
//
public class AdaptateurNoeudDOM {
private org.w3c.dom.Node m_NoeudDOM;
public AdaptateurNoeudDOM (org.w3c.dom.Node NoeudDOM) {
m_NoeudDOM = NoeudDOM;
}
//
// Méthode pour convertir un AdaptateurNoeudDOM en String
//
public String toString() {
String Résultat = NOMS_TYPES_NOEUDS[m_NoeudDOM.getNodeType()];
String nom = m_NoeudDOM.getNodeName();
if (nom.length () != 0 && !nom.startsWith("#")) {
Résultat += ": " + nom;
}
if (m_NoeudDOM.getNodeValue() != null) {
if (Résultat.startsWith("ProcInstr")) {
Résultat += ", ";
} else {
Résultat += ": ";
}
//
// Nettoyage au cas où le texte commencerait par des blancs
// ou un saut de ligne
//
String s = m_NoeudDOM.getNodeValue().trim();
int ndxNouvelleLigne = s.indexOf("\n");
if (ndxNouvelleLigne >= 0) {
s = s.substring(0, ndxNouvelleLigne);
}
if (s.length () > 0) {
Résultat += s;
} else {
Résultat = "(vide)";
}
}
return Résultat;
}
//
// Cherche l'index d'un enfant
//
public int index(AdaptateurNoeudDOM Enfant) {
int NombreEnfants = compterEnfants();
for (int i = 0; i < NombreEnfants; i++) {
AdaptateurNoeudDOM anDOM = getEnfant(i);
if (Enfant.m_NoeudDOM == anDOM.m_NoeudDOM) {
return i;
}
}
return -1; // Ne devrait pas se rendre ici.
}
public int compterEnfants() {
return m_NoeudDOM.getChildNodes().getLength();
}
public AdaptateurNoeudDOM getEnfant (int ndx) {
org.w3c.dom.Node noeudDOM =
m_NoeudDOM.getChildNodes().item(ndx);
return new AdaptateurNoeudDOM(noeudDOM);
}
}
//
// Adapte un document pour en faire un modèle de JTree
// (en gros, du «boilerplate code»)
//
public class AdaptateurDOMTreeModel
implements javax.swing.tree.TreeModel
{
private Vector <TreeModelListener> m_ListeObservateurs;
private Document m_Document;
public AdaptateurDOMTreeModel (Document doc) {
m_ListeObservateurs= new Vector<TreeModelListener>();
m_Document = doc;
}
//
// Opérations de base d'un TreeModel
//
public Object getRoot() {
return new AdaptateurNoeudDOM(m_Document);
}
public boolean isLeaf(Object aNode) {
AdaptateurNoeudDOM node = (AdaptateurNoeudDOM) aNode;
return node.compterEnfants() <= 0;
}
public int getChildCount(Object parent) {
AdaptateurNoeudDOM noeud = (AdaptateurNoeudDOM) parent;
return noeud.compterEnfants();
}
public Object getChild(Object parent, int index) {
AdaptateurNoeudDOM noeud = (AdaptateurNoeudDOM) parent;
return noeud.getEnfant(index);
}
public int getIndexOfChild(Object parent, Object enfant) {
AdaptateurNoeudDOM noeud = (AdaptateurNoeudDOM) parent;
return noeud.index((AdaptateurNoeudDOM) enfant);
}
public void valueForPathChanged(TreePath path, Object newValue) {
// sans intérêt pour nous
}
//
// On doit implémenter celles-ci mais on ne s'en servira pas
//
public void addTreeModelListener(TreeModelListener observateur) {
if ( observateur != null && ! m_ListeObservateurs.contains( observateur ) ) {
m_ListeObservateurs.addElement( observateur );
}
}
public void removeTreeModelListener(TreeModelListener observateur) {
if ( observateur != null ) {
m_ListeObservateurs.removeElement( observateur );
}
}
//
// ...
//
public void fireTreeNodesChanged( TreeModelEvent e ) {
Enumeration observateurs = m_ListeObservateurs.elements();
while ( observateurs.hasMoreElements() ) {
TreeModelListener observateur =
(TreeModelListener) observateurs.nextElement();
observateur.treeNodesChanged( e );
}
}
public void fireTreeNodesInserted( TreeModelEvent e ) {
Enumeration observateurs = m_ListeObservateurs.elements();
while ( observateurs.hasMoreElements() ) {
TreeModelListener observateur =
(TreeModelListener) observateurs.nextElement();
observateur.treeNodesInserted( e );
}
}
public void fireTreeNodesRemoved( TreeModelEvent e ) {
Enumeration observateurs = m_ListeObservateurs.elements();
while ( observateurs.hasMoreElements() ) {
TreeModelListener observateur =
(TreeModelListener) observateurs.nextElement();
observateur.treeNodesRemoved( e );
}
}
public void fireTreeStructureChanged( TreeModelEvent e ) {
Enumeration observateurs = m_ListeObservateurs.elements();
while ( observateurs.hasMoreElements() ) {
TreeModelListener observateur =
(TreeModelListener) observateurs.nextElement();
observateur.treeStructureChanged( e );
}
}
}
}
Le code proposé à droite consomme un document XML selon une stratégie DOM et en fait une représentation arborescente à l'écran.
Si vous examinez attentivement le tout, vous remarquerez que le code consommant le document y est plus petit que le code relié à l'affichage—consommer un document XML n'est pas une tâche très douloureuse, surtout en comparaison avec une tâche pleine de petits détails comme celle de gérer une interface personne/ machine.
Notez que j'utilise ici un dérivé de la classe ConsommateurDOM, à laquelle vous pouvez vous référer pour plus de détails.