Utilisation de l'API DOM de Python avec la bibliothèque PyXML

Lebrun Jonathan

Nous allons utiliser Python et l'API DOM pour lire des données issues d'un fichier XML.

- Titre : Utilisation de l'API DOM de Python avec la bibliothèque PyXML

- Auteur : Lebrun Jonathan

- Parution : 29 octobre 2004

- Mise à jour : 28 avril 2020

- Licence : 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 ® 2013 Lebrun Jonathan. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Introduction

- II. Le fichier XML

- III. Lecture du XML et création des objets

- III-A. Le script python complet

- III-B. La classe Personne

- III-C. La classe Adresse

- III-D. La classe TransformXmlToPersonnes

- IV. Conclusion

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 TAG Personnes qui auront des nom, prénom et adresse. Ces informations seront injectées dans les objets python appropriés que nous pourrons 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 bases du XML et de Python. Il vous faut la dernière version de python ainsi que le module PyXML.

II - Le fichier XML

<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'adresses 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'étofferont.

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 une 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 contrepartie 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

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 suivants est manquant : 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

class Personne:

nom = None

prenom = None

adresse = Adresse()

def __init__(self):

pass

Cette classe va nous servir à créer des objets de type 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

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

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.

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ément du document. On appelle cette façon de travailler une « lazy instanciation ». 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.

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 suivants est manquant : 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 une liste dans laquelle nous allons stocker chaque objet Personne créé. En premier lieu nous regardons si la liste a 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 » contenus 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.

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.

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.