2010-09-28 5 views
4

J'adapte le code suivant (créé via le conseil dans this question), qui a pris un fichier XML et sa DTD et les a convertis dans un format différent. Pour ce problème que la section de chargement est important:Python xml etree DTD à partir d'une source StringIO?

xmldoc = open(filename) 

parser = etree.XMLParser(dtd_validation=True, load_dtd=True)  
tree = etree.parse(xmldoc, parser) 

Cela a bien fonctionné, tout en utilisant le système de fichiers, mais je convertir en exécuter via un framework web, où les deux fichiers sont chargés via un formulaire.

Chargement du fichier xml fonctionne très bien:

tree = etree.parse(StringIO(data['xml_file']) 

Mais comme DTD est lié dans le haut du fichier xml, l'instruction suivante échoue:

parser = etree.XMLParser(dtd_validation=True, load_dtd=True) 
tree = etree.parse(StringIO(data['xml_file'], parser) 

Via this question, j'ai essayé :

etree.DTD(StringIO(data['dtd_file']) 
tree = etree.parse(StringIO(data['xml_file']) 

Alors que la première ligne ne provoque pas d'erreur, la seconde tombe sur entités unicode la DTD est destiné à ramasser (et ce, dans la version du système de fichiers):

XMLSyntaxError: Entity 'eacute' not defined, line 4495, column 46

Comment puis-je sur le chargement correctement cette DTD?

+0

Ajouté une prime car j'aimerais vraiment une réponse plus détaillée, en utilisant le code ci-dessus comme contexte. –

Répondre

5

Voici un exemple court mais complet, utilisant la technique de résolution personnalisée @Steven mentionnée.

from StringIO import StringIO 
from lxml import etree 

data = dict(
    xml_file = '''<?xml version="1.0"?> 
<!DOCTYPE x SYSTEM "a.dtd"> 
<x><y>&eacute;zz</y></x> 
''', 
    dtd_file = '''<!ENTITY eacute "&#233;"> 
<!ELEMENT x (y)> 
<!ELEMENT y (#PCDATA)> 
''') 

class DTDResolver(etree.Resolver): 
    def resolve(self, url, id, context): 
     return self.resolve_string(data['dtd_file'], context) 

xmldoc = StringIO(data['xml_file']) 
parser = etree.XMLParser(dtd_validation=True, load_dtd=True) 
parser.resolvers.add(DTDResolver()) 
try: 
    tree = etree.parse(xmldoc, parser) 
except etree.XMLSyntaxError as e: 
    # handle xml and validation errors 
+0

Votre exemple fonctionne de manière isolée, mais j'utilise des objets StringIO pour les fichiers xml_file et dtd_file - je peux le faire fonctionner avec ceux-ci .... –

+0

I J'ai essayé de mettre data = dict (fichier_xml_fichier = fichier_xml.read(), fichier_dtd = fichier_dtd.read()) ... ce qui (semble) m'avancer plus loin, mais maintenant j'ai - UnicodeEncodeError: 'codec ascii' peut t encoder le caractère u '\ xe9' dans la position 28: ordinal pas dans la gamme (128) - Je pensais que la DTD ramasserait sur ceci ..... –

+0

Correction - UnicodeEncodeError était sans rapport avec votre code. dtd_file.read() etc semble avoir fait le travail, même si je ne sais pas si c'est la meilleure approche. –

1

Vous pourriez probablement utiliser un custom resolver. Les docs donnent en fait un exemple de faire ceci pour fournir un dtd.

+0

ce lien est rompu – Alfe

+0

@Alfe: le lien brisé est maintenant corrigé – Steven