¿Compatibilidad con Python ElementTree para analizar entidades XML desconocidas?

Tengo un conjunto de archivos XML súper simples para analizar … pero … usan entidades personalizadas definidas. No necesito asignarlos a los personajes, pero sí deseo analizarlos y actuar sobre cada uno. Por ejemplo:

  [admin_level]='5' &maxscale_zoom11;   

Hay una sugerencia tentadora en http://effbot.org/elementtree/elementtree-xmlparser.htm que XMLParser tiene soporte de entidad limitado, pero no puedo encontrar los métodos mencionados, todo da errores:

  #!/usr/bin/python ## ## Where's the entity support as documented at: ## http://effbot.org/elementtree/elementtree-xmlparser.htm ## In Python 2.7.1+ ? ## from pprint import pprint from xml.etree import ElementTree from cStringIO import StringIO parser = ElementTree.ElementTree() #parser.entity["maxscale_zoom11"] = unichr(160) testf = StringIO('&maxscale_zoom11;') tree = parser.parse(testf) #tree = parser.parse(testf,"XMLParser") for node in tree.iter('foo'): print node.text 

Lo que dependiendo de cómo se ajusten los comentarios da:

 xml.etree.ElementTree.ParseError: undefined entity: line 1, column 5 

o

 AttributeError: 'ElementTree' object has no attribute 'entity' 

o

 AttributeError: 'str' object has no attribute 'feed' 

Para aquellos curiosos, el XML es del proyecto mapnik de OpenStreetMap .

No estoy seguro de si se trata de un error en ElementTree o qué, pero debe llamar a UseForeignDTD (Verdadero) al analizador de expatriados para que se comporte como lo hizo en el pasado.

Es un poco intrincado, pero puedes hacer esto creando tu propia instancia de ElementTree.Parser, llamando al método en su instancia de xml.parsers.expat, y luego pasándolo a ElementTree.parse ():

 from xml.etree import ElementTree from cStringIO import StringIO testf = StringIO('&moo_1;') parser = ElementTree.XMLParser() parser.parser.UseForeignDTD(True) parser.entity['moo_1'] = 'MOOOOO' etree = ElementTree.ElementTree() tree = etree.parse(testf, parser=parser) for node in tree.iter('foo'): print node.text 

Esto da salida a “MOOOOO”

O usando una interfaz de mapeo:

 from xml.etree import ElementTree from cStringIO import StringIO class AllEntities: def __getitem__(self, key): #key is your entity, you can do whatever you want with it here return key testf = StringIO('&moo_1;') parser = ElementTree.XMLParser() parser.parser.UseForeignDTD(True) parser.entity = AllEntities() etree = ElementTree.ElementTree() tree = etree.parse(testf, parser=parser) for node in tree.iter('foo'): print node.text 

Esto da como resultado “moo_1”

Una solución más compleja sería la subclase ElementTree.XMLParser y corregirla allí.

Como @cnelson ya señaló en un comentario, la solución elegida aquí no funcionará en Python 3.

Finalmente lo tengo funcionando. Citado de este Q & A.

Inspirados en esta publicación , podemos anteponer parte de la definición XML al contenido HTML en bruto entrante, y luego ElementTree funcionará fuera de la caja.

Esto funciona tanto para Python 2.6, 2.7, 3.3, 3.4.

 import xml.etree.ElementTree as ET html = ''' 
Some reasonably well-formed HTML content.
It is not unusual to see   in an HTML page.
''' magic = ''' ]>''' # You can define more entities here, if needed et = ET.fromstring(magic + html)