2011-12-05 15 views
6

Tengo un formato de archivo heredado que estoy convirtiendo a XML para su procesamiento. La estructura se puede resumir como:LXML - Ordenar orden de clasificación

<A> 
    <A01>X</A01> 
    <A02>Y</A02> 
    <A03>Z</A03> 
</A> 

la parte numérica de las etiquetas puede ir entre 01 y 99 y puede haber lagunas. Como parte del procesamiento, ciertos registros pueden tener etiquetas adicionales agregadas. Después de que el procesamiento se complete, estoy convirtiendo el archivo de nuevo al formato heredado al recorrer el árbol. Los archivos son razonablemente grandes (~ 150,000 nodos).

Un problema con esto es que algunos programas que usan el formato heredado asumen que las etiquetas (o más bien los campos en el momento de su conversión) estarán en orden alfanumérico pero de forma predeterminada se agregarán nuevas etiquetas al final de la rama que luego hace que salgan del iterador en el orden incorrecto.

Puedo usar xpath para buscar el hermano anterior basado en el nombre de la etiqueta cada vez que vengo a agregar una nueva etiqueta, pero mi pregunta es si hay una forma más simple de ordenar el árbol justo antes de exportarlo.

Editar:

Creo que he resumido sobre la estructura.

Un registro puede contener varios niveles, como se describe anteriormente para dar algo como:

<X> 
    <X01>1</X01> 
    <X02>2</X02> 
    <X03>3</X03> 
    <A> 
     <A01>X</A01> 
     <A02>Y</A02> 
     <A03>Z</A03> 
    </A> 
    <B> 
     <B01>Z</B02> 
     <B02>X</B02> 
     <B03>C</B03> 
    </B> 
</X> 
+2

no estoy tan seguro el esquema XML está muy bien pensado. ¿No son A01 y A02 el mismo tipo de cosas? Deben compartir el mismo nombre de elemento. El número quizás sea un atributo, no una parte del nombre de la etiqueta. Además, los nombres de las etiquetas deberían ser más legibles que eso, por supuesto, pero me doy cuenta de que pueden ser solo un ejemplo. –

+0

Desafortunadamente no tengo control del formato heredado y esta es una traducción directa de cómo almacena los datos en pares clave/valor. En el archivo original podría decir "A01 = Bob" y las aplicaciones saben que ese número contiene el nombre. – George

+0

Hay muchas formas de implementar esto en XML, pero el que ha mostrado aquí no es una traducción muy semántica. Su esquema sería complicado y cambiante. Yo sugeriría ' value' donde item es lo que A01, A02 representa. –

Respuesta

17

Es posible escribir un helper fu nction para insertar un nuevo elemento en el lugar correcto, pero sin saber más sobre la estructura es difícil hacerlo genérico.

Aquí está un ejemplo corto de clasificar los elementos secundarios en todo el documento:

from lxml import etree 

data = """<X> 
    <X03>3</X03> 
    <X02>2</X02> 
    <A> 
     <A02>Y</A02> 
     <A01>X</A01> 
     <A03>Z</A03> 
    </A> 
    <X01>1</X01> 
    <B> 
     <B01>Z</B01> 
     <B02>X</B02> 
     <B03>C</B03> 
    </B> 
</X>""" 

doc = etree.XML(data,etree.XMLParser(remove_blank_text=True)) 

for parent in doc.xpath('//*[./*]'): # Search for parent elements 
    parent[:] = sorted(parent,key=lambda x: x.tag) 

print etree.tostring(doc,pretty_print=True) 

Rendimiento:

<X> 
    <A> 
    <A01>X</A01> 
    <A02>Y</A02> 
    <A03>Z</A03> 
    </A> 
    <B> 
    <B01>Z</B01> 
    <B02>X</B02> 
    <B03>C</B03> 
    </B> 
    <X01>1</X01> 
    <X02>2</X02> 
    <X03>3</X03> 
</X> 
+0

Gracias - la función lamba hace justo lo que necesito. – George

+0

Gracias ...También encontré útil este artículo: http://wiki.python.org/moin/HowTo/Sorting http://www.secnetix.de/olli/Python/lambda_functions.hawk – Homer6

+0

No entiendo por qué usas 'parent [:] = 'en la asignación. – Sdwdaw

4

Puede tipo que los elementos XML como esto:

from operator import attrgetter 
from lxml import etree 

root = etree.parse(xmlfile) 
children = list(root) 
sorted_list = sorted(children, key=attrgetter('tag')) 

Si esto funciona muy lento, que sólo podría ordenar los nombres de las etiquetas y obtener el nodo usando xpath:

tag_list = [item.tag for item in root] 
sorted_taglist = sorted(tag_list) 
Cuestiones relacionadas