10.7. Assembler les pièces

Vous avez déjà parcouru un long chemin. Portez votre regard en arrière et voyez comment rassembler toutes ces étapes.

Pour commencer, il s'agit d'un script qui prend ses arguments sur la ligne de commande, en utilisant le module getopt.


def main(argv):                         
...
    try:                                
        opts, args = getopt.getopt(argv, "hg:d", ["help", "grammar="])
    except getopt.GetoptError:          
...
    for opt, arg in opts:               
...

Vous créez une nouvelle instance de la classe KantGenerator et vous lui passez un fichier de grammaire et une source de données qui peuvent ou non avoir été spécifiés à la ligne de commande.

    k = KantGenerator(grammar, source)

L'instance KantGenerator charge automatiquement la grammaire, qui est un fichier XML. Vous utilisez la fonction taillée sur-mesure, openAnything, pour ouvrir le fichier (qui pourrait être stocké dans un fichier local ou sur un serveur web distant), puis vous utilisez les fonctions de traitement intégrées du module minidom pour analyser le document XML en un arbre d'objets Python.

    def _load(self, source):
        sock = toolbox.openAnything(source)
        xmldoc = minidom.parse(sock).documentElement
        sock.close()

Tiens, au passage, vous tirez avantage de votre connaissance de la structure d'un document XML pour mettre en place un petit cache de références, constitué simplement des éléments du document XML.

    def loadGrammar(self, grammar):                         
        for ref in self.grammar.getElementsByTagName("ref"):
            self.refs[ref.attributes["id"].value] = ref     

Si vous avez spécifié une source de données à la ligne de commande, vous l'utilisez; autrement vous décortiquez la grammaire en recherchant la référence de plus haut niveau (celle qui n'est référencée par aucune autre) et vous l'utilisez comme point de départ.

    def getDefaultSource(self):
        xrefs = {}
        for xref in self.grammar.getElementsByTagName("xref"):
            xrefs[xref.attributes["id"].value] = 1
        xrefs = xrefs.keys()
        standaloneXrefs = [e for e in self.refs.keys() if e not in xrefs]
        return '<xref id="%s"/>' % random.choice(standaloneXrefs)

Maintenant vous décortiquez la source de données. La source est aussi du XML et vous analysez ses noeuds un par un. Pour conserver un code séparé et plus maintenable, vous utilisez des gestionnaires distincts pour chaque type de noeud.

    def parse_Element(self, node): 
        handlerMethod = getattr(self, "do_%s" % node.tagName)
        handlerMethod(node)

Vous parcourez la grammaire, en analysant tous les enfants de chaque élément p,

    def do_p(self, node):
...
        if doit:
            for child in node.childNodes: self.parse(child)

en remplaçant les éléments choice par un enfant choisi aléatoirement,

    def do_choice(self, node):
        self.parse(self.randomChildElement(node))

et en remplaçant les éléments xref par l'un des enfants, choisi aléatoirement, de l'élément ref correspondant, que vous avez préalablement mis en cache.

    def do_xref(self, node):
        id = node.attributes["id"].value
        self.parse(self.randomChildElement(self.refs[id]))

Finalement, vous poussez l'analyse jusqu'au texte brut,

    def parse_Text(self, node):    
        text = node.data
...
            self.pieces.append(text)

qu'il ne vous reste plus qu'à afficher.


def main(argv):                         
...
    k = KantGenerator(grammar, source)
    print k.output()