I. Introduction

DOM : Document Object Model. Il s'agit d'une API permettant la manipulation de fichiers XML. Grâce à cette API, nous allons pouvoir lire un fichier XML mais également ajouter de nouveaux éléments à ce fichier. DOM peut-être vu comme une arborescence de fichier. Il faut également savoir qu'avec l'API dom de python, tout est élément ou nœud, même le texte. Ainsi, si le TAG <A> contient « Bonjour » cela voudra dire que le nœud A de type ELEMENT contient le nœud « Bonjour » de type TEXT. Mais tout ceci sera plus clair avec le code (du moins je l'espère).
Dans ce tutoriel, nous allons simplement lire un fichier pour transformer les TAG en objets python que nous aurons définis. Nous aurons donc un XML avec des TAGs Personnes qui auront des nom, prénoms et adresse. Ces informations seront injectées dans les objets python appropriés que nous pourront par la suite manipuler. Pour l'instant, nous nous arrêterons là. Par la suite j'ajouterai la manière d'enregistrer les modifications.
Il est important que vous connaissiez les base du XML et de Python. Il vous faut la dernière version de python ainsi que le module PyXML.

II. Le fichier XML

 
Sélectionnez
<quil>

    <personne>

        <nom>Durant</nom>

        <prenom>Stephan</prenom>

        <adresse>

                <ville>Bruxelles</ville>

        </adresse>

    </personne>

    <personne>

        <nom>Dupont</nom>

        <prenom>Henri</prenom>

        <adresse/>

    </personne>

</quil>

Ce fichier XML représente un petit carnet d'adresse personnel. Évidemment, il est peu fourni en informations ? car il va nous servir à réaliser notre petit exercice. Vous pourrez, comme exercice, tenter d'ajouter de nouveaux éléments qui l'étoffera.

Nous avons un nœud (ou TAG XML) principal s'appelant « quil » (ben oui ! pourquoi pas !). Il ne peut y avoir qu'un seul élément à ce niveau de hiérarchie du fichier XML. On peut voir un celui-ci comme un disque dur. Ainsi le premier élément est l'équivalent de la racine de votre disque. Les autres nœuds imbriqués correspondront à des répertoires et sous répertoires et sous répertoires et ainsi de suite. Sauvegardez ce fichier sous « personnes.xml » avec l'éditeur de votre choix.

Mais au fait, pourquoi choisir XML plutôt qu'un fichier plat ou encore un base de données ?
La réponse, vous la trouverez sur le net au travers de sites spécialisés dans les comparatifs. Moi tout ce que je peux faire à ce sujet est donné mon humble avis. XML permet d'avoir une structure clairement définie ce qui lui donne un avantage par rapport aux fichiers plats. Maintenant par rapport aux SGBD, le principal apport est la facilité d'utilisation du XML, mais également la portabilité de l'application ainsi créée. On pourra voyager d'un PC à l'autre avec son application et ses données. Pas besoin de réseau. Une clef USB qui contiendra le soft complet avec des données continuellement à jour. Cela, un SGBD ne le permet pas de manière simple. La contre-partie est la sécurité et la gestion des données s'il s'agit d'une application avec beaucoup de lien entre données. C'est à vous de peser le pour et le contre et de faire votre choix.

III. Lecture du XML et création des objets

III-A. Le script python complet

 
Sélectionnez
class Personne:

    nom = None

    prenom = None

    adresse = Adresse()

    

    def __init__(self):

        pass



class Adresse:

    ville = None

    

    def __init__(self):

        pass

    

class TransformXmlToPersonnes:



    __currentNode__ = None

    __personneList__ = None

    

    def __init__(self):

        self.readXml()



    def readXml(self):

        from xml.dom.minidom import parse

        self.doc = parse('E:/python/samplexml/personnes.xml')



    def getRootElement(self):

        if self.__currentNode__ == None:

            self.__currentNode__ = self.doc.documentElement

        return self.__currentNode__



    def getPersonnes(self):

        if self.__personneList__ != None:

            return 

        self.__personneList__ = []

        for personnes in self.getRootElement().getElementsByTagName("personne"):

            if personnes.nodeType == personnes.ELEMENT_NODE:

                p = Personne()

                try:

                    p.nom = self.getText(personnes.getElementsByTagName("nom")[0])

                    p.prenom = self.getText(personnes.getElementsByTagName("prenom")[0])

                    p.adresse = self.getAdresse(personnes.getElementsByTagName("adresse")[0])

                except:

                    print 'Un des TAGS suivant est manquents : nom, prenom, adresse'

                self.__personneList__.append(p)

        return self.__personneList__



    def getAdresse(self, node):

        adress = Adresse()

        try:

            adress.ville = self.getText(node.getElementsByTagName("ville")[0])

        except:

            adress.ville = None

        return adress

                

    def getText(self, node):

        return node.childNodes[0].nodeValue

    

if __name__ == "__main__":

    x=TransformXmlToPersonnes()

    print x.getPersonnes()[1].nom

Vous pouvez enregistrer ce script sous « personnes.py ». Nous allons décortiquer ce script pas à pas avec la description des différentes classes et méthodes.

III-B. La classe Personne

 
Sélectionnez
class Personne:

    nom = None

    prenom = None

    adresse = Adresse()

    

    def __init__(self):

        pass

Cette classe va nous servir à créer des objets de types personnes qui vont contenir toutes les informations recueillies dans le fichier XML pour une personne. L'attribut Adresse est une classe décrite ci-après. La méthode « __init__ » est le constructeur de la classe qui ne fait rien.

III-C. La classe Adresse

 
Sélectionnez
class Adresse:

    ville = None

    

    def __init__(self):

        pass

Cette ne contient qu'un attribut qui est la ville où habite la personne. Vous pourrez améliorer les informations par vous-même par la suite.

III-D. La classe TransformXmlToPersonnes

 
Sélectionnez
class TransformXmlToPersonnes:

    __currentNode__ = None

    __personneList__ = None

    

    def __init__(self):

        self.readXml()



    def readXml(self):

        from xml.dom.minidom import parse

        self.doc = parse('personnes.xml')

Il s'agit de la classe qui va permettre le traitement du fichier XML. La méthode « __init__ » fait appel à la méthode « readXML » qui va lire le fichier xml grâce à la méthode « parse » importée depuis « xml.dom.minidom ». Cette méthode prend en argument le nom du fichier xml à traiter, c'est-à-dire à transformer en un objet compréhensible pour python. Ci-après nous allons étudier les autres méthodes de notre classe.

 
Sélectionnez
def getRootElement(self):

        if self.__currentNode__ == None:

            self.__currentNode__ = self.doc.documentElement

        return self.__currentNode__

On regarde si on a déjà lu le premier élément du fichier (dans notre cas « quil »). Si oui, on ne fait que retourner l'attribut __currentNode__, sinon, on prend le premier élémént du document. On appelle cette façon de travailler une « lazy instantiation ». On va par la suite travailler à partir de ce premier élément comme s'il s'agissait d'un répertoire de base (C: sous win ou / sous Un*x par exemple). On va ainsi descendre de plus en plus bas dans notre hiérarchie de nœud.

 
Sélectionnez
def getPersonnes(self):

        if self.__personneList__ != None:

            return self.__personneList__

        self.__personneList__ = []

        for personnes in self.getRootElement().getElementsByTagName("personne"):

            if personnes.nodeType == personnes.ELEMENT_NODE:

                p = Personne()

                try:

                    p.nom = self.getText(personnes.getElementsByTagName("nom")[0])

                    p.prenom = self.getText(personnes.getElementsByTagName("prenom")[0])

                    p.adresse = self.getAdresse(personnes.getElementsByTagName("adresse")[0])

                    self.__personneList__.append(p)

                except:

                    print 'Un des TAGS suivant est manquants : nom, prenom, adresse'

        return self.__personneList__

Il s'agit de la méthode la plus complexe de notre exercice, car il va s'agir de transformer les nœuds personnes en objet Personne. Comme il existe plusieurs personnes, nous allons créer un liste dans laquelle nous allons stocker chaque objet Personne créé. En premier lieu nous regardons si la liste à déjà été créée et si oui on retourne l'objet déjà existant. Sinon, on crée une nouvelle liste vide.

Ensuite on crée une boucle for sur tous les éléments avec comme nom « personne » contenu dans l'élément root (ici : « quil »). Pour chacun de ces éléments, on regarde s'il s'agit d'un type de nœud ELEMENT. Si oui, on crée un nouvel objet Personne et on tente de récupérer les valeurs des nœuds nom, prenom et adresse en utilisant les méthodes « getText » et « getAdresse ». Dans ce cas précis, comme je sais qu'il n'y a qu'un nom par personne, je lui demande l'élément 0. Effectivement la méthode « getElementsByTagName » renvoie une liste. Si un des nœuds n'existe pas dans le fichier, j'imprime une erreur. On peut améliorer cela en renvoyant une exception particulière. On assigne à chaque variable la valeur appropriée et on ajoute l'objet p à notre liste que l'on retourne lorsque l'itération est terminée.

 
Sélectionnez
def getAdresse(self, node):

        adress = Adresse()

        try:

            adress.ville = self.getText(node.getElementsByTagName("ville")[0])

        except:

            adress.ville = None

        return adress

Cette méthode reprend la même logique que la précédente pour la création de l'adresse pour une personne.

 
Sélectionnez
def getText(self, node):

        return node.childNodes[0].nodeValue

Et enfin celle-ci retourne le texte pour un nœud particulier. Ainsi pour le nœud « nom », je vais récupérer le texte mais comme le texte est également un nœud, je suis obligéde faire « node.childNode[0] ». Le « nodeValue » est pour récupérer la valeur.

IV. Conclusion

Comme vous pouvez le voir il est assez simple de manipuler un fichier XML avec python et l'API DOM. Pour les Java-istes, ça ressemble assez à du JDOM et donc on retrouve vite ses marques.