Parse el archivo XML en el objeto de Python

Tengo un archivo XML que se parece a esto:

  some filename.mp3 Gogo (after 3.0) 131 joint stereo 00:02:43 5,236,644 no good 44100 6255 ..... and so forth ......  ....  

Quiero leerlo en un objeto python, algo así como una lista de diccionarios. Debido a que el marcado es absolutamente fijo, estoy tentado a usar expresiones regulares (soy bastante bueno en usarlas). Sin embargo, pensé que verificaría si alguien sabe cómo evitar fácilmente las expresiones regulares aquí. Sin embargo, no tengo mucha experiencia con SAX u otro análisis, pero estoy dispuesto a aprender.

Estoy deseando que me muestren cómo se hace esto rápidamente sin expresiones regulares en Python. ¡Gracias por tu ayuda!

Mi sombrero de queridos cargadores SD está apagado para ti si crees que una expresión regular es más fácil que esto:

 #!/usr/bin/env python import xml.etree.cElementTree as et sxml="""   some filename.mp3 Gogo (after 3.0) 131   another filename.mp3 iTunes 128   """ tree=et.fromstring(sxml) for el in tree.findall('file'): print '-------------------' for ch in el.getchildren(): print '{:>15}: {:<30}'.format(ch.tag, ch.text) print "\nan alternate way:" el=tree.find('file[2]/Name') # xpath print '{:>15}: {:<30}'.format(el.tag, el.text) 

Salida:

 ------------------- Name: some filename.mp3 Encoder: Gogo (after 3.0) Bitrate: 131 ------------------- Name: another filename.mp3 Encoder: iTunes Bitrate: 128 an alternate way: Name: another filename.mp3 

Si su atracción por una expresión regular es escasa, aquí hay un poco de comprensión de lista igualmente incomprensible para crear una estructura de datos:

 [(ch.tag,ch.text) for e in tree.findall('file') for ch in e.getchildren()] 

Lo que crea una lista de tuplas de los elementos secundarios XML de en el orden de los documentos:

 [('Name', 'some filename.mp3'), ('Encoder', 'Gogo (after 3.0)'), ('Bitrate', '131'), ('Name', 'another filename.mp3'), ('Encoder', 'iTunes'), ('Bitrate', '128')] 

Con unas pocas líneas más y un poco más de reflexión, obviamente, puede crear cualquier estructura de datos que desee desde XML con ElementTree. Es parte de la distribución Python.

Editar

Código de golf está en marcha!

 [{item.tag: item.text for item in ch} for ch in tree.findall('file')] [ {'Bitrate': '131', 'Name': 'some filename.mp3', 'Encoder': 'Gogo (after 3.0)'}, {'Bitrate': '128', 'Name': 'another filename.mp3', 'Encoder': 'iTunes'}] 

Si su XML solo tiene la sección de file , puede elegir su golf. Si su XML tiene otras tags, otras secciones, debe tener en cuenta la sección en la que se encuentran los niños y deberá usar findall

Hay un tutorial sobre ElementTree en Effbot.org

Utilice ElementTree . No es necesario / no quiere meterse con un gadget de solo pyexpat como pyexpat … solo terminaría reinventando ElementTree de manera parcial y deficiente.

Otra posibilidad es lxml, que es un paquete de terceros que implementa la interfaz de ElementTree y más.

Actualizar Alguien comenzó a jugar código de golf; Aquí está mi entrada, que en realidad crea la estructura de datos que solicitó:

 # xs = """ etc etc >> import xml.etree.cElementTree as et >>> from pprint import pprint as pp >>> pp([dict((attr.tag, attr.text) for attr in el) for el in et.fromstring(xs)]) [{'Bitrate': '131', 'Encoder': 'Gogo (after 3.0)', 'Frame': 'no', 'Frames': '6255', 'Freq.': '44100', 'Length': '00:02:43', 'Mode': 'joint stereo', 'Name': 'some filename.mp3', 'Quality': 'good', 'Size': '5,236,644'}, {'Bitrate': '0', 'Name': 'foo.mp3'}] >>> 

Probablemente desearía tener un “atributo” de asignación de dict para funciones de conversión:

 converters = { 'Frames': int, 'Size': lambda x: int(x.replace(',', '')), # etc } 

También he estado buscando una forma sencilla de transformar datos entre documentos XML y estructuras de datos de Python, algo similar a la biblioteca XML de Golang que le permite especificar de forma declarativa cómo asignar estructuras de datos a XML.

No pude encontrar dicha biblioteca para Python, así que escribí una para satisfacer mi necesidad llamada declxml para el procesamiento declarativo de XML.

Con declxml, crea procesadores que definen de forma declarativa la estructura de su documento XML. Los procesadores se utilizan para realizar tanto el análisis como la serialización, así como un nivel básico de validación.

El análisis de estos datos XML en una lista de diccionarios con declxml es sencillo

 import declxml as xml xml_string = """   some filename.mp3 Gogo (after 3.0) 131   another filename.mp3 iTunes 128   """ processor = xml.dictionary('encspot', [ xml.array(xml.dictionary('file', [ xml.string('Name'), xml.string('Encoder'), xml.integer('Bitrate') ]), alias='files') ]) xml.parse_from_string(processor, xml_string) 

Lo que produce el siguiente resultado.

 {'files': [ {'Bitrate': 131, 'Encoder': 'Gogo (after 3.0)', 'Name': 'some filename.mp3'}, {'Bitrate': 128, 'Encoder': 'iTunes', 'Name': 'another filename.mp3'} ]} 

¿Quieres analizar los datos en objetos en lugar de diccionarios? Usted puede hacer eso también

 import declxml as xml class AudioFile: def __init__(self): self.name = None self.encoder = None self.bit_rate = None def __repr__(self): return 'AudioFile(name={}, encoder={}, bit_rate={})'.format( self.name, self.encoder, self.bit_rate) processor = xml.array(xml.user_object('file', AudioFile, [ xml.string('Name', alias='name'), xml.string('Encoder', alias='encoder'), xml.integer('Bitrate', alias='bit_rate') ]), nested='encspot') xml.parse_from_string(processor, xml_string) 

Lo que produce la salida.

 [AudioFile(name=some filename.mp3, encoder=Gogo (after 3.0), bit_rate=131), AudioFile(name=another filename.mp3, encoder=iTunes, bit_rate=128)] 

Si tienes una función estática que convierte un XML a un objeto, sería algo como esto

 @classmethod def from_xml(self,xml_str): #create XML Element root = ET.fromstring(xml_str) # create a dict from it d = {ch.tag: ch.text for ch in root.getchildren()} # return the object, created with **kwargs called from the Class, that's why its classmethod return self(**d)