P
'
t
i
t
e
C
h
a
t
t
e
 
spacer~ MY IMAGINARY FRIEND THINKS YOU HAVE MENTAL PROBLEMS Articles | Connexion
 
~Python et XML

 Présentation

Python constitue un langage souple et puissant. A l'aise dans de nombreux domaines, il ne déroge pas à la règle quand il s'agit de XML. Que ce soit pour DOM ou SAX, Python offre par défaut plusieurs librairies.
 Sommaire

2. SAX
3. DOM

 Introduction

Les distributions 2.x de Python contiennent les librairies xml.dom, xml.sax et xmllib. Cette dernière ne susbsiste que par souci de compatibilité avec les précédentes versions du langage. Un autre module existe, directement lié à un parser spécifique nommé expat. Ce module s'intitule xml.parsers.expat. Nous nous baserons sur ce module pour illustrer l'emploi de SAX avec Python.


 SAX

La première étape conduisant à la lecture d'un document XML par l'intermédiaire de SAX réside dans la création d'une instance du parser.

from xml.parsers.expat import ParserCreate
parser = ParserCreate()
       
      
JextCopier dans Jext | Jext | Plugin Codegeek
Décidemment, Python n'en finit pas de nous étonner par sa simplicité. L'objet ainsi créé représente une instance de XMLParser. Deux méthodes particulières requièrent notre attention : Parse(data) et Parse(file). La première de ces deux méthodes sert à analyser un document XML sous forme de chaîne de caractères. La seconde permet de gérer un document désigné par un flux de lecture possédant la fonction read(nbytes). Il peut par exemple s'agir d'un fichier.

parser.Parse(open("~/fichier.xml"))
       
      
JextCopier dans Jext
Contrairement à Java, la définition des gestionnaires SAX ne passe pas par la création d'une nouvelle classe héritant d'une interface spécifique. L'objet XMLParser met à profit l'aisance avec laquelle Python peut manipuler les fonctions. Prenons l'exemple de la fonction XmlDecHandler(). Elle possède trois arguments version, encoding et standalone. Cette méthode, dans le cadre de SAX, est invoquée lorsque la déclaration <?xml?> du document se voit lue.

Afin de remplacer l'implémentation d'origine par celle de votre cru, vous devez tout simplement définir une nouvelle fonction :

def debutDocumentXML(version, encoding, standalone):
  print "Document XML de version", version

parser = ParserCreate()
parser. XmlDecHandler = debutDocumentXML
       
      
JextCopier dans Jext
Si vous parvenez à maîtriser le principe pour une des fonctions du parser, il ne vous reste plus qu'à l'appliquer aux autres fonctions dudit parser. Vous trouverez un récapitulatif des fonctions les plus importantes dans l'encadré numéro un.

Note 1
  • StartElementHandler(name, attributes) : balise ouvrante
  • EndElementHandler(name) : balise fermante
  • CharacterDataHandler(data) : contenu d'une balise
  • CommentHandler(data) : commentaire
  • StartCdataSectionHandler() : début d'une section CDATA
  • EndCdataSectionHandler() : fin d'une section CDATA
  • DefaultHandler(data) : gestion des caractères non supportés

Le script d'exemple lit un fichier XML pour en extraire des actions Python. Chacune d'entre elles est identifée par un nom. Le script demande ensuite d'entrer un nom. Si une action correspond au nom entré, le script l'exécute.

Nous utilisons pour cela les méthodes StartElementHandler, EndElementHandler et CharacterDataHandler. La première méthode permet de connaître le nom de l'action. La troisième lit le code Python à exécuter. Pour finir, la seconde méthode inclut l'action dans un dictionnaire.

Voici un exemple de fichier XML géré par notre application :

<python>
  <action name="hello">print "*" * 10, " hello ", "*" * 10</action>
  <action name="bye">print "=" * 10, " bye'cha ", "=" * 10</action>
</python>
       
      
JextCopier dans Jext
En tapant "hello" dans le programme, nous exécuterons le code : print "*" * 10, " hello ", "*" * 10. Vous trouverez de nombreux objets relatifs à SAX dans les modules xml.sax.


 DOM

Le Document Object Model a deux finalités : la lecture des documents XML et la création de documents XML. En Python se cotoient deux librairies DOM : xml.dom et xml.dom.minidom. La seconde offre un intérêt réel puisqu'elle se veut plus rapide et plus légère que la première. Cela se traduit malheureusement par la perte de certains objets de l'API DOM.

Pour produire un document XML à travers DOM le programmeur doit tout d'abord créer un nouveau document. L'objet Document contient des fonctions de création de noeud. Tout élément d'un arbre XML correspond à une implémentation de l'objet Node. Le Document est un Node, Element (les balises) est un Node ou encore Attr (les attributs) est un Node. Les Node possèdent deux choses indispensables : le champ childNodes, qui contient une liste des Node descendants, et la méthode appendChild(node) qui permet d'ajouter des enfants au noeud.

D'autres attributs de l'objet s'avèrent très pratique pour lire les arbres DOM :
  • parentNode représente le noeud parent
  • firstChild correspond au premier fils
  • lastChild incarne le dernier fils
  • previousSibling pointe sur le noeud précédent celui-ci dans son parent
  • nextSibling pointe sur le noeud suivant dans le parent

Un objet Document permet donc de créer des noeuds. Les méthodes à invoquer sont les suivantes :
  • createElement(name) pour créer une balise
  • createTextNode(data) pour créer un contenu de balise
  • createComment(data) pour créer un commentaire
  • createAttribute(name) pour créer un attribut

L'adjonction d'un attribut à un élément donné passe par l'appel à la méthode à setAttributeNode(node) ou encore à setAttribute(name, value). Enfin, les documents comme les éléments possèdent la fonction getElementsByTagName(name) qui renvoie un objet NodeListe contenant l'ensemble des balises filles portant le nom précisé. Il s'agit d'une des fonctions les plus puissantes de DOM.

Le listing suivant retrace le code source d'un script créant un nouveau document DOM et imprimant son code XML.

from xml.dom.minidom import Document

xmldoc = Document()
xmltag = xmldoc.createElement("root")
xmlchild = xmldoc.createElement("child")
xmlchild.appendChild(xmldoc.createTextNode("hello world !"))
xmlchild.setAttribute("name", "enfant")
xmltag.appendChild(xmlchild)
xmldoc.appendChild(xmltag)

print xmldoc.toxml()
       
      
JextCopier dans Jext | Jext | Plugin Codegeek
L'exécution de cet exemple provoque l'affichage du code XML qui suit :

<?xml version="1.0" ?>
<root><child name="enfant">hello world !</child></root>
       
      
JextCopier dans Jext
Grâce à DOM nous pouvons également parcourir des documents lus depuis une source externe. La méthode parse(source) remplit cet objectif. L'argument "source" de la méthode doit désigner chemin de fichier ou un flux de lecture. La méthode parseString(str) sert à lire une chaîne de caractères. Ces deux fonctions renvoient une instance de l'objet Document.

L'énumération des noeuds descendant du noeud racine d'un document ainsi obtenu (le noeud racine se désigne par le champ documentElement de Document) nous permet d'avoir un aperçu rapide d'un document XML :

xmldoc = parse("document.xml")
for n in xmldoc.documentElement.childNodes:
    if n.nodeType == Node.ELEMENT_NODE:
        print n.nodeName
       
      
JextCopier dans Jext
Vous pouvez faire l'expérience de retirer la clause de condition portant sur le nodeType de chaque noeud. Vous constaterez alors que chaque retour à la ligne et chaque indentation du fichier est notifiée comme un noeud de type texte. Nous pourrions aussi dresser la liste de toutes les balises <section> du document. Pour cela, il conviendrait de remplacer childNodes par getElementsByTagName("section") dans l'exemple précédent.

La manipulation des documents XML en Python ne demande que peu d'efforts eu égard à la simplicité des API et du langage même. Cela fait de Python un langage de choix pour l'exploration de 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