example - python xml to dict
Estrategia iterparse de elementtree (2)
Este es un enfoque posible: mantenemos una lista de rutas y miramos hacia atrás para encontrar el (los) nodo (s) padre (s).
path = []
for event, elem in ET.iterparse(file_path, events=("start", "end")):
if event == ''start'':
path.append(elem.tag)
elif event == ''end'':
# process the tag
if elem.tag == ''name'':
if ''members'' in path:
print ''member''
else:
print ''nonmember''
path.pop()
Tengo que manejar documentos XML que son lo suficientemente grandes (hasta 1 GB) y analizarlos con python. Estoy usando la función iterparse() (análisis de estilo SAX).
Mi preocupación es la siguiente, imagina que tienes un xml como este
<?xml version="1.0" encoding="UTF-8" ?>
<families>
<family>
<name>Simpson</name>
<members>
<name>Homer</name>
<name>Marge</name>
<name>Bart</name>
</members>
</family>
<family>
<name>Griffin</name>
<members>
<name>Peter</name>
<name>Brian</name>
<name>Meg</name>
</members>
</family>
</families>
El problema es, por supuesto, saber cuándo obtengo un apellido (como Simpsons) y cuándo recibo el nombre de uno de ese miembro de la familia (por ejemplo, Homer)
Lo que he estado haciendo hasta ahora es usar "interruptores" que me dirán si estoy dentro de una etiqueta de "miembros" o no, el código se verá así
import xml.etree.cElementTree as ET
__author__ = ''moriano''
file_path = "test.xml"
context = ET.iterparse(file_path, events=("start", "end"))
# turn it into an iterator
context = iter(context)
on_members_tag = False
for event, elem in context:
tag = elem.tag
value = elem.text
if value :
value = value.encode(''utf-8'').strip()
if event == ''start'' :
if tag == "members" :
on_members_tag = True
elif tag == ''name'' :
if on_members_tag :
print "The member of the family is %s" % value
else :
print "The family is %s " % value
if event == ''end'' and tag ==''members'' :
on_members_tag = False
elem.clear()
Y esto funciona bien ya que la salida es
The family is Simpson
The member of the family is Homer
The member of the family is Marge
The member of the family is Bart
The family is Griffin
The member of the family is Peter
The member of the family is Brian
The member of the family is Meg
Mi preocupación es que con este (simple) ejemplo tuve que crear una variable adicional para saber en qué etiqueta estaba (on_members_tag) imaginar con los verdaderos ejemplos xml que tengo que manejar, tienen más etiquetas anidadas.
También tenga en cuenta que este es un ejemplo muy reducido, por lo que puede suponer que puedo estar enfrentando un xml con más etiquetas, más etiquetas internas y tratando de obtener diferentes nombres de etiquetas, atributos, etc.
Así que la pregunta es. ¿Estoy haciendo algo horriblemente estúpido aquí? Siento que debe haber una solución más elegante para esto.
pulldom es excelente para esto. Obtienes un flujo de saxofón. Puede recorrer la secuencia y, cuando encuentre un nodo en el que esté interesado, cargue ese nodo en un fragmento de dom.
import xml.dom.pulldom as pulldom
import xpath # from http://code.google.com/p/py-dom-xpath/
events = pulldom.parse(''families.xml'')
for event, node in events:
if event == ''START_ELEMENT'' and node.tagName==''family'':
events.expandNode(node) # node now contains a dom fragment
family_name = xpath.findvalue(''name'', node)
members = xpath.findvalues(''members/name'', node)
print(''family name: {0}, members: {1}''.format(family_name, members))
salida:
family name: Simpson, members: [u''Hommer'', u''Marge'', u''Bart'']
family name: Griffin, members: [u''Peter'', u''Brian'', u''Meg'']