Utilisation de l'API DOM de Python avec la bibliothèque PyXML.
Par
Lebrun Jonathan (Quilovnic Concept)
Nous allons utiliser Python et l'API DOM pour lire des données issues d'un fichier XML.
Introduction
I. Le fichier XML
II. Lecture du XML et création des objets
A. Le script python complet
B. La classe Personne
C. La classe Adresse
D. La classe TransformXmlToPersonnes
Conclusion
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 noeud, même le texte. Ainsi, si le TAG <A> contient "Bonjour" cela voudra dire que le noeud A de type ELEMENT
contient le noeud "Bonjour" de type TEXT. Mais tout ceci sera plus clair avec le code (du moins je l'espère).
Dans ce tutorial, 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.
I. 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'adresse personnel. Evidemment, 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 noeud (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 noeuds imbriqués correspondront à des répertoires et sous répertoires et sous 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 donner 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.
II. Lecture du XML et création des objets
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 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.
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 types personnes qui vont contenir toutes les
informations receuillies 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.
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.
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 regarder 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 noeud.
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
noeuds 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 dant l'élément root (ici : "quil").
Pour chacun de ces éléments, on regarde s'il s'agit d'un type de noeud ELEMENT. Si oui, on crée un nouvel objet Personne
et on tente de récupérer les valeurs des noeuds 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 noeuds 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 noeud particulier. Ainsi pour le noeud "nom", je vais récupérer le texte
mais comme le texte est également un noeud, je suis obligé de faire "node.childNode[0]" . Le "nodeValue" est pour
récupérer la valeur.
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.
Ce document est issu de http://www.developpez.com et reste la propriété exclusive de son auteur.
La copie, modification et/ou distribution par quelque moyen que ce soit est soumise à l'obtention préalable de l'autorisation de l'auteur.
|