2010-09-01 6 views
1

J'essaie de créer un simple analyseur XML où chaque schéma XML différent possède sa propre classe d'analyseur, mais je ne peux pas déterminer quelle est la meilleure façon de procéder. Ce que je en effet voudrait faire quelque chose comme ceci:Métaprogrammation Python pour l'analyse XML

in = sys.stdin 
xmldoc = minidom.parse(in).documentElement 

xmlParser = xmldoc.nodeName 
parser = xmlParser() 
out = parser.parse(xmldoc) 

Je ne suis pas aussi tout à fait sûr si je reçois le document correctement le nom de la racine, mais c'est l'idée: créer un objet d'une classe avec un nom semblable à la racine du document et utilisez la fonction parse() dans cette classe pour analyser et gérer l'entrée.

Quel serait le moyen le plus simple d'y parvenir? J'ai lu des articles sur l'introspection et les modèles, mais je n'ai pas encore réussi à le comprendre. J'ai fait une chose similaire avec Java dans le passé et AFAIK, Ruby rend également cela simple. Quelle est la façon pythonienne?

+1

Cette question est sans valeur sans détails. Par "analyse", voulez-vous dire "extraire des données de DOM"? Ou voulez-vous construire un analyseur XML entier à partir de zéro? Ou voulez-vous dire un * validateur *? ...? – delnan

+0

Comment cela serait-il pertinent? Je veux être en mesure d'appeler une classe Python basée sur le nom de la racine du document d'un fichier XML. Je ne pense pas que ce que je vais faire dans ces cours soit pertinent. – Makis

Répondre

1

Comme l'a souligné Mark dans son commentaire, pour obtenir une référence à une classe dont vous connaissez le nom lors de l'exécution, vous utilisez getattr.

doc = minidom.parse(sys.stdin) 
# is equivalent to 
doc = getattr(minidom, "parse")(sys.stdin) 

Voici une version corrigée de votre pseudo-code.

from xml.dom import minidom 
import sys 
import myParsers # a module containing your parsers 

xmldoc = minidom.parse(sys.stdin).documentElement 

myParserName = xmldoc.nodeName 
myParserClass = getattr(myParsers, myParserName) 
# create an instance of myParserClass by calling it with the documentElement 
parser = myParserClass(xmldoc) 
# do whatever you want with the instance of your parser class 
output = parser.generateOutput() 

getattr retournera un AttributeError si l'attribut n'existe pas, donc vous pouvez envelopper l'appel dans un essai ... sauf ou passer un troisième argument à getattr, Wich sera retourné si l'ISN d'attribut » t trouvé.

1

Je pense que la plupart des programmeurs python utiliseraient simplement lxml pour analyser leur xml. Si vous voulez toujours envelopper cela dans les cours, mais comme le dit Delnan dans son commentaire, vous ne comprenez pas vraiment ce que vous voulez vraiment dire.

from lxml import etree 

tree = etree.parse('my_doc.xml') 
for element in tree.getroot(): 
    ... 

Quelques notes secondaires, si d'autres programmeurs vont être la lecture de votre code, vous devriez essayer au moins à peu près suivre PEP 8. Plus important encore, vous devriez vraiment pas céder à builtins comme « dans "

+0

Ceci est juste un serveur de test simple où ce script reçoit un fichier XML et retourne quelque chose. Je pensais que je le rendrais un peu plus intelligent pour qu'il soit facile d'ajouter plus de tests au xml reçu (vérification de validité, etc.) par schéma (c'est-à-dire que je pourrais juste vérifier que le fichier xml est correct). Mon plan était d'avoir les noms des parsers après le document racine, mais cela est hors de propos car j'étais plus intéressé par la partie réflexion/introspection de ma question. C'est à dire. est-il possible de créer un objet si nous avons le nom de l'objet en tant que chaîne? – Makis

+0

Eh bien, il est simple d'instancier une classe existante si vous connaissez son nom. Vous pouvez simplement utiliser parser_class = getattr (module, class_name). Je pense que c'est ce que vous demandez. Si vous voulez générer dynamiquement une classe basée sur un nom de chaîne, vous pouvez le faire, mais je ne pense pas que ce soit ce que vous voulez. – Mark