library example etree dict create python xml sax elementtree iterparse

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'']