LXML - Порядок сортировки тегов - PullRequest
6 голосов
/ 05 декабря 2011

У меня есть устаревший формат файла, который я конвертирую в XML для обработки.Структура может быть представлена ​​следующим образом:

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

Числовая часть тегов может быть от 01 до 99, и могут быть пробелы.В рамках обработки некоторых записей могут быть добавлены дополнительные теги.После завершения обработки я преобразую файл обратно в унаследованный формат, обходя дерево.Файлы достаточно большие (~ 150 000 узлов).

Проблема в том, что некоторые программы, использующие устаревший формат, предполагают, что теги (или, скорее, поля к моменту их преобразования) будут иметь буквенно-цифровую форму.порядок, но по умолчанию новые теги будут добавлены в конец ветви, что приведет к тому, что они выйдут из итератора в неправильном порядке.

Я могу использовать xpath, чтобы найти предшествующего брата по имени тега каждыйПришло время добавить новый тег, но мой вопрос заключается в том, существует ли более простой способ сортировки дерева сразу перед экспортом?

Редактировать:

Я думаю, что я более кратко изложилструктура.

Запись может содержать несколько уровней, как описано выше, чтобы получить что-то вроде:

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

17 голосов
/ 05 декабря 2011

Можно написать вспомогательную функцию для вставки нового элемента в правильное место, но, не зная больше о структуре, сложно сделать ее общей.

Вот краткий пример сортировки дочерних элементов по всему документу:

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)

Уступая:

<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>
4 голосов
/ 05 декабря 2011

Вы можете отсортировать элементы XML следующим образом:

from operator import attrgetter
from lxml import etree

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

Если это работает слишком медленно, вы можете просто отсортировать имена тегов и получить узел, используя xpath:

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