2011-12-05 17 views
6

Mam starsze formaty plików, które konwertuję do formatu XML w celu przetworzenia. Strukturę można podsumować następująco:LXML - sortowanie znaczników Kolejność sortowania

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

Część numeryczna znaczników może mieć od 01 do 99 i mogą występować przerwy. W ramach przetwarzania niektóre rekordy mogą zawierać dodatkowe znaczniki. Po zakończeniu przetwarzania konwertuję plik z powrotem do wcześniejszego formatu, podążając za drzewem. Pliki są dość duże (~ 150 000 węzłów).

Problem polega na tym, że niektóre programy, które używają starszego formatu, zakładają, że znaczniki (lub pola w momencie ich konwersji) będą w porządku alfabetycznym, ale domyślnie nowe znaczniki zostaną dodane na końcu gałąź, która powoduje, że wychodzą z iteratora w niewłaściwej kolejności.

Mogę użyć xpath do znalezienia poprzedniego rodzeństwa na podstawie nazwy znacznika za każdym razem, gdy przychodzę, aby dodać nowy tag, ale moje pytanie brzmi, czy istnieje prostszy sposób posortowania drzewa na raz tuż przed eksportem?

Edytuj:

Myślę, że podsumowałem już strukturę.

Rekord może zawierać kilka poziomów, jak opisano powyżej, aby dać coś takiego:

<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

nie jestem taki pewien schemat XML jest bardzo dobrze przemyślane. Czy A01 i A02 nie są tego samego typu? Powinny mieć tę samą nazwę elementu. Numer powinien być atrybutem, a nie częścią nazwy znacznika. Ponadto nazwy znaczników powinny być bardziej czytelne niż to, oczywiście, ale zdaję sobie sprawę, że mogą być tylko przykładem. –

+0

Niestety, nie mam kontroli nad dotychczasowym formatem i jest to bezpośrednie tłumaczenie sposobu przechowywania danych w parach klucz/wartość. W oryginalnym pliku może to być "A01 = Bob", a aplikacje wiedzą, że numer zawiera imię. – George

+0

Istnieje wiele sposobów na wdrożenie tego w XML, ale ten, który tu pokazałeś, nie jest bardzo semantycznym tłumaczeniem. Twój schemat będzie skomplikowany i ciągle się zmienia. Proponuję ' wartość' gdzie item jest tym, co reprezentuje A01, A02. –

Odpowiedz

17

Możliwe jest napisanie pomocnika fu nction, aby wstawić nowy element w odpowiednim miejscu, ale nie wiedząc więcej o strukturze, trudno jest go uogólnić.

Oto krótki przykład sortowania elementów podrzędnych w całym dokumencie:

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) 

Uzyskano

<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

Dzięki - funkcja lamba robi dokładnie to, czego potrzebuję. – George

+0

Dzięki ...Znalazłem również przydatny artykuł: http://wiki.python.org/moin/HowTo/Sorting http://www.secnetix.de/olli/Python/lambda_functions.hawk – Homer6

+0

Nie rozumiem, dlaczego używasz 'rodzica [:] = 'w przypisaniu. – Sdwdaw

4

można sortować ciebie elementów XML tak:

from operator import attrgetter 
from lxml import etree 

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

jeśli ten działa zbyt wolno, może po prostu posortuj nazwy znaczników i uzyskaj węzeł za pomocą ścieżki xpath:

tag_list = [item.tag for item in root] 
sorted_taglist = sorted(tag_list) 
Powiązane problemy