P
'
t
i
t
e
C
h
a
t
t
e
 
spacer~ I'M NOT AS THINK AS YOU DRUNK I AM !! Articles | Connexion
 
~Java et DOM

 Présentation

Les parsers XML Java offrant un support de l'API DOM ouvrent une porte sur de multiples possibilitées. Outre la création aisée de documents XML, DOM facilite la navigation en leur sein.
 Sommaire


 Introduction

La tâche à laquelle nous allons nous atteler n'est pas des moindres : nous allons réaliser un système d'archivage. Ledit système sera similaire à la commande "tar". Notre outil aura pour finalité d'archiver une arborescence de fichiers au cour d'un document XML. De plus, l'archive conservera le contenu des fichiers de l'arborescence au format GZIP afin de réduire son propre poids.

La structure d'une arborescence de fichiers se révélant très proche d'un arbre XML, la définition de notre DTD n'apporte aucune problématique. Voici un exemple de fichier archive :

<directory name="home">
  <directory name="gfx">
    <file name=".bashrc">data</file>
  </directory>
</directory>
       
      
JextCopier dans Jext | Jext | Plugin Codegeek
La DTD complète de nos documents et les sources de notre programme se téléchargent ici. Deux complications apparaissent à ce niveau.

Comment nous assurer que les caractères correspondant aux fichiers compressés seront acceptés par le parser ? Et comment nous assurer que le parser comprendra les caractères composants les noms de fichiers et/ou répertoires ? La seconde question se résoud instantanément en adoptant l'encodage ISO-8859-1 dans la déclaration <?xml?> des documents.

La gestion des données compressées nécessite une transformation particulière. A l'instar des gestionnaires de courrier électronique avec les pièces jointes, nous allons utilise un encodage nommé Base64. Cet encodage relativement simple transforme tout octet de donnée en caractères alphanumériques (lettres, chiffres, et quelques caractères supplémentaires). Bien entendu, il incombera à l'application de pouvoir restaurer une archive.


 Java DOMine

Une fois n'est pas coutume, notre choix se portera sur le parser Xerces afin d'assurer le support de XML. Le projet Apache nommé SOAP offre une classe servant au codage et au décodage de données au format Base64. Cette dernière se verra employée par notre outil. Le fichier HDMirror.java contient l'intégralité du code source de l'application. Suivant l'opération requise par l'utilisateur, l'API DOM servira de générateur ou de lecteur de document XML.

Lors d'une opération de création d'archive, la méthode main() invoque la méthode archiveHD(). Cette méthode se compose de trois opérations principales : création d'un document DOM, lancement du processus d'archivage, écriture du fichier archive. La création du document DOM tient en quelques lignes :

Document doc = createDOMDocument();
Element root = doc.getDocumentElement();
root.setAttribute("name", baseDirectory.getName());
       
      
JextCopier dans Jext | Jext | Plugin Codegeek
La première instruction appelle la méthode createDOMDocument() sur laquelle nous allons revenir. La seconde instruction récupère l'élément racine du document. Enfin, un attribut "name" se voit ajouté à la balise racine. La racine du document correspond au répertoire de base de l'archive.

Voici à présent comment la méthode createDOMDocument() génère un nouveau document :

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new InputSource(
  new StringReader("<directory></directory>")));
       
      
JextCopier dans Jext
Le principe consiste à lire une chaîne de caractères contenant la balise racine du document XML. Une fois notre document mis en place, nous devons le "remplir". A chacun des sous-répertoires ou fichiers contenu dans le répertoire de base de l'archive correspondra un nouvel élement DOM. La création d'éléments passe par la méthode document.createElement(String name).

C'est la méthode archiveFile() qui réalise tout le travail d'archivage. Elle reçoit en paramètre le répertoire à archiver ainsi que l'élément DOM parent. Par l'entremise de la méthode addChild() de la classe Node, nous sommes en mesure d'ajouter des enfants à un élément.

En DOM, tout correspond à un type Node : les attributs, les éléments, les textes, les commentaires... Le traitement d'un répertoire s'effectue de la sorte :

Element directory = doc.createElement("directory");
directory.setAttribute("name", files[i].getName());
element.appendChild(directory);
archiveFile(files[i], doc, directory);
       
      
JextCopier dans Jext
La troisième instruction a pour rôle de définir le nouvel élément comme fils de l'élément "père". Vous constaterez le caractère récursif de la méthode. La gestion des fichiers repose sur un principe similaire. Cependant le programme ajoute un noeud texte au nouvel élément correspondant au fichier.

_file.appendChild(doc.createTextNode(
  Base64.encode(stringWriter.toByteArray())));
       
      
JextCopier dans Jext
Le contenu du noeud texte s'encode en Base64. Au préalable une opération de compression se voit effectuée. Pour terminer, la méthode archiveHD() écrit le document DOM dans un fichier. La transformation de l'objet Document en chaîne de caractères composée de code XML se voit effectuée par l'intermédiaire de la classe XMLSerializer de Xerces. Reportez-vous à la méthode getXMLCode() pour plus d'informations.


 Ce n'est pas DOMain la veille

La recontruction d'une arborescence de fichiers depuis un document XML trouve place dans la méthode dearchiveHD(). Contrairement à la méthode d'archivage, celle de restauration n'effectue que deux actions principales : la lecture du document XML et la restauration à proprement parler. La lecture du document se trouve dans l'appel à la méthode createDOMDocument(String uri). Cette méthode reprend les mêmes opérations que la méthode précédent createDOMDocument(). Néanmoins, au lieu de parser une chaîne de caractères, elle parse un URI. La méthode dearchiveFile() possède également un caractère récursif.

Son rôle consiste à parcourir l'ensemble des noeuds enfant d'un élément donné. Le premier élément est bien sûr incarné par l'élément racine du document. Le programmeur se voit en mesure de connaître la liste des noeuds enfant d'un élément grâce à la méthode getChildNodes() qui renvoie un objet de type NodeList.

Pourtant, tous les noeuds enfants ne sont pas des éléments. C'est pourquoi il se révèle impératif de vérifier la nature du noeud courant :

Node node = childs.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE)
  // traitement
       
      
JextCopier dans Jext | Jext | Plugin Codegeek
Puis que nous sommes à présent certains de la nature du noeud, il s'avère possible d'effectuer un transtypage : Element e = (Element) node. Si le nom de la balise, e.getTagName(), correspond à un répertoire, le travail devient simple :

File file = new File(root, e.getAttribute("name"));
file.mkdirs();
dearchiveFile(file, e);
       
      
JextCopier dans Jext
Ces quelques lignes créent tout simplement un nouveau répertoire avant de poursuivre l'exécution récursivement. Les choses se compliquent dans le cas des fichiers. Nous devons tout d'abord vérifier que l'élément possède bien des descendants. La fonction hasChildNodes() résoud le problème.

Théoriquement, le noeud texte que nous cherchons à utiliser pour "remplir" le fichier doit apparaître en premier dans la liste des enfants :

node = e.getFirstChild();
if (node.getNodeType() == Node.TEXT_NODE)
  // décompression/écriture
       
      
JextCopier dans Jext
La fin du processus concerne le décodage et la décompression des données contenues par les balises <file>. Le contenu textuel de ces balises se récupère par l'intermédiaire de la méthode getNodeValue() de l'objet Node.

Le programme s'exécute par la commande "./xmlarchiver.sh [-archive|-dearchive] répertoire fichier.xml".



par Romain Guy
romain.guy@jext.org
http://www.jext.org
Dernière mise à jour : 14/10/2006



 
#ProgX©2005 Mathieu GINOD - Romain GUY - Erik LOUISE