Сортировать xml с помощью python по тегу

#python #xml #sorting

#python #xml #сортировка

Вопрос:

У меня есть xml

 <root>
 <node1>
  <B>text</B>
  <A>another_text</A>
  <C>one_more_text</C>
 </node1>
 <node2>
  <C>one_more_text</C>
  <B>text</B>
  <A>another_text</A>
 </node2>
</root>
  

Я хочу получить вывод, подобный:

 <root>
 <node1>
  <A>another_text</A>
  <B>text</B>
  <C>one_more_text</C>
 </node1>
 <node2>
  <A>another_text</A>
  <B>text</B>
  <C>one_more_text</C>
 </node2>
</root>
  

Я попытался с помощью некоторого кода, подобного:

 from xml.etree import ElementTree as et

tr = et.parse(path_in)
root = tr.getroot()
for children in root.getchildren():
    for child in children.getchildren():
        # sort it

tr.write(path_out)        
  

Я не могу использовать стандартную функцию sort и sorted , потому что она отсортирована неправильно (не по тегу).
Заранее спасибо.

Ответ №1:

Вам нужно:

  • получите дочерние элементы для каждого «узла» верхнего уровня
  • сортируйте их по tag атрибуту (имя узла)
  • сброс дочерних узлов каждого узла верхнего уровня

Пример рабочего кода:

 from operator import attrgetter
from xml.etree import ElementTree as et

data = """  <root>
 <node1>
  <B>text</B>
  <A>another_text</A>
  <C>one_more_text</C>
 </node1>
 <node2>
  <C>one_more_text</C>
  <B>text</B>
  <A>another_text</A>
 </node2>
</root>"""


root = et.fromstring(data)
for node in root.findall("*"):  # searching top-level nodes only: node1, node2 ...
    node[:] = sorted(node, key=attrgetter("tag"))

print(et.tostring(root))
  

С принтами:

 <root>
 <node1>
  <A>another_text</A>
  <B>text</B>
  <C>one_more_text</C>
 </node1>
 <node2>
  <A>another_text</A>
  <B>text</B>
  <C>one_more_text</C>
  </node2>
</root>
  

Обратите внимание, что здесь мы не используем getchildren() метод (на самом деле он устарел начиная с Python 2.7) — используя тот факт, что каждый Element экземпляр является итеративным для дочерних узлов.

Ответ №2:

Из аналогичного вопроса :

 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>
  

Вы можете найти более подробную информацию здесь:http://effbot.org/zone/element-sort.htm