Nous allons, dans ce tuto voir comment manipuler un fichier de données au format XML via l'API SAX (Simple Api for Xml). Cette API est basée sur modèle événementiel : le parseur SAX va parcourir le document XML et pour chaque élément syntaxique qu'il va rencontrer, il va invoquer une « callback » (une méthode) correspondant au type de l'élément syntaxique.
Commencons par parler du fichier de données : il est au format XML et contient des définitions de figures géométriques. Le but du programme sera de lire les données de chaque figure puis de les tracer dans une interface graphique de type Tkinter. Voici ce fichier.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<?xml version="1.0" ?> <Shapes> <Circle x="100" y="100" radius="20"> <Color red="255" green="0" blue="255" /> </Circle> <Square x="300" y="100" length="50"> <Color red="255" green="0" blue="0" /> </Square> <Circle x="200" y="200" radius="30"> <Color red="0" green="0" blue="255" /> </Circle> <Square x="100" y="300" length="40"> <Color red="0" green="255" blue="0" /> </Square> </Shapes> |
La librairie SAX pour Python est localisée dans le paquetage xml.sax
.
Le fonctionnement d'un parseur SAX repose notamment sur la classe ContentHandler
. Celle-ci définie les différentes « callback », les différentes méthodes qui seront invoquées
lors du traitment du fichier XML. Notez bien qu'à ce niveau, les méthodes ne font encore rien : il sera nécessaire de dériver cette classe pour dire quoi faire de concrêt.
Voici le contenu de cette classe (je l'ai volontairement simplifié et j'ai aussi supprimer les commentaires.)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
class ContentHandler: def startDocument(self): pass def startElement(self, name, attrs): pass def characters(self, content): pass def endElement(self, name): pass def endDocument(self): pass # . . . |
Cette exemple de code est un peu subtile : il met en oeuvre de l'héritage multiple. Nous avons une classe, MyWindow
, qui est à la fois une fenêtre (grâce à l'héritage de la classe Tk
)
et à la fois un handler SAX (grâce à l'héritage de ContentHandler
). Cette fenêtre/handler contient un Canvas
(une zone de tracè) dans lequel nous allons dessiner les figures
géométriques.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
#!/usr/bin/python3 from tkinter import Canvas, Tk from xml.sax import parse from xml.sax.handler import ContentHandler class MyWindow(Tk, ContentHandler): def __init__(self): Tk.__init__(self) self.title("Shaper V1.0") self.__canvas = Canvas(self, width=400, height=400, background="white") parse("Shapes.xml", self) self.__canvas.pack() def startDocument(self): print( "Start document parsing" ) def startElement(self, name, attrs): if name=="Circle": self.__currentShape = dict(attrs) elif name=="Square": self.__currentShape = dict(attrs) elif name=="Color": self.__currentShape["color"] = "#%02x%02x%02x" % \ (int(attrs["red"]), int(attrs["green"]), int(attrs["blue"])) def endElement(self, name): if name=="Circle": radius = int(self.__currentShape["radius"]) x1 = int(self.__currentShape["x"]) - radius y1 = int(self.__currentShape["y"]) - radius x2 = int(self.__currentShape["x"]) + radius y2 = int(self.__currentShape["y"]) + radius self.__canvas.create_oval(x1, y1, x2, y2, fill=self.__currentShape["color"]) print("Draw Circle") elif name=="Square": delta = int(self.__currentShape["length"]) / 2 x1 = int(self.__currentShape["x"]) - delta y1 = int(self.__currentShape["y"]) - delta x2 = int(self.__currentShape["x"]) + delta y2 = int(self.__currentShape["y"]) + delta self.__canvas.create_rectangle(x1, y1, x2, y2, fill=self.__currentShape["color"]) print("Draw Square") def endDocument(self): print( "End document parsing" ) window = MyWindow() window.mainloop() |
Voici le résultat produit par cette application.
Améliorations / Corrections
Vous avez des améliorations (ou des corrections) à proposer pour ce document : je vous remerçie par avance de m'en faire part, cela m'aide à améliorer le site.
Emplacement :
Description des améliorations :