2011-12-05 4 views
6

Ho un formato di file legacy che sto convertendo in XML per l'elaborazione. La struttura può essere riassunta come:LXML - Ordine tag di ordinamento

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

La parte numerica dei tag può andare da 01 a 99 e ci possono essere lacune. Come parte dell'elaborazione, alcuni record potrebbero aver aggiunto tag aggiuntivi. Una volta completata l'elaborazione, sto riconvertendo il file al formato precedente eseguendo iterwalking dell'albero. I file sono ragionevolmente grandi (~ 150.000 nodi).

Un problema con questo è che alcuni software che utilizzano il formato legacy presuppongono che i tag (o piuttosto i campi al momento della conversione) saranno in ordine alfanumerico, ma per impostazione predefinita i nuovi tag verranno aggiunti alla fine di il ramo che poi li fa uscire dall'iteratore nell'ordine sbagliato.

Posso usare xpath per trovare il fratello precedente basato sul nome del tag ogni volta che vengo ad aggiungere un nuovo tag, ma la mia domanda è se c'è un modo più semplice per ordinare l'albero immediatamente prima dell'esportazione?

Edit:

credo di aver sintetizzato sopra la struttura.

Un record può contenere diversi livelli come descritto in precedenza per dare qualcosa di simile:

<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

io non sono così sicuro lo schema XML è molto ben pensato. Non sono A01 e A02 lo stesso tipo di cose? Dovrebbero condividere lo stesso nome di elemento. Il numero dovrebbe forse essere un attributo, non parte del nome del tag. Inoltre, i nomi dei tag dovrebbero essere più leggibili di quello, ovviamente, ma mi rendo conto che potrebbero essere solo un esempio. –

+0

Purtroppo non ho il controllo del formato precedente e questa è una traduzione diretta di come memorizza i dati in coppie chiave/valore. Nel file originale potrebbe dire "A01 = Bob" e le applicazioni quindi sapranno che il numero contiene il nome. – George

+0

Ci sono molti modi per implementarlo in XML, ma quello che hai mostrato qui non è una traduzione semantica. Il tuo schema sarebbe complicato e in continua evoluzione. Vorrei suggerire ' valore' dove item è la cosa che rappresenta A01, A02. –

risposta

17

È possibile scrivere un helper fu nction per inserire un nuovo elemento nel posto giusto, ma senza saperne di più sulla struttura è difficile renderlo generico.

Ecco un breve esempio di ordinamento elementi figlio attraverso l'intero 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) 

Cedendo:

<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

Grazie - la funzione lamba fa proprio quello di cui ho bisogno. – George

+0

Grazie ...Ho trovato utile anche questo articolo: http://wiki.python.org/moin/HowTo/Sorting http://www.secnetix.de/olli/Python/lambda_functions.hawk – Homer6

+0

Non capisco perché usi 'parent [:] = 'nell'assegnazione. – Sdwdaw

4

È possibile ordinare voi elementi XML in questo modo:

from operator import attrgetter 
from lxml import etree 

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

Se questo correre troppo lento, si potrebbe solo ordina i nomi dei tag e ottieni il nodo usando xpath:

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