2016-10-20 3 views
0

У меня есть несколько «корневых» тегов с именем детей. Я хочу отсортировать блоки «root», упорядоченные по алфавиту с помощью элемента «name». Попробовал lxml/etree/minidom, но не смог заставить его работать ... Я не могу заставить его анализировать значение внутри тегов, а затем сортировать родительские корневые теги.Сортировка тегов XML с помощью дочерних элементов Python

<?xml version='1.0' encoding='UTF-8'?> 
    <roots> 
    <root> 
     <path>//1.1.1.100/Alex</path> 
     <name>Alex Space</name> 
    </root> 
    <root> 
     <path>//1.1.1.101/Steve</path> 
     <name>Steve Space</name> 
    </root> 
    <root> 
     <path>//1.1.1.150/Bethany</path> 
     <name>Bethanys</name> 
    </root> 
</roots> 

Вот что я пробовал:

import xml.etree.ElementTree as ET 

    def sortchildrenby(parent, child): 
     parent[:] = sorted(parent, key=lambda child: child) 


tree = ET.parse('data.xml') 
root = tree.getroot() 

sortchildrenby(root, 'name') 
for child in root: 
    sortchildrenby(child, 'name') 


tree.write('output.xml') 
+0

Итак, вы хотите, чтобы имя было первым? –

ответ

1

Если вы хотите поместить имя узлов первым:

x = """ 
    <roots> 
    <root> 
     <path>//1.1.1.100/Alex</path> 
     <name>Alex Space</name> 
    </root> 
    <root> 
     <path>//1.1.1.101/Steve</path> 
      <name>Bethanys</name> 
    </root> 
    <root> 
     <path>//1.1.1.150/Bethany</path> 
     <name>Steve Space</name> 
    </root> 
</roots>""" 

import lxml.etree as et 
tree = et.fromstring(x) 

for r in tree.iter("root"): 
    r[:] = sorted(r, key=lambda ch: -(ch.tag == "name")) 

print(et.tostring(tree).decode("utf-8")) 

Который даст вам:

<roots> 
    <root> 
     <name>Alex Space</name> 
    <path>//1.1.1.100/Alex</path> 
     </root> 
    <root> 
     <name>Bethanys</name> 
    <path>//1.1.1.101/Steve</path> 
      </root> 
    <root> 
     <name>Steve Space</name> 
    <path>//1.1.1.150/Bethany</path> 
     </root> 
</roots> 

Но нет никакой необходимости, чтобы разобраться, если вы просто хотите, чтобы добавить их первыми , вы можете просто удалить и вставить имя в индекс 0:

import lxml.etree as et 
tree = et.fromstring(x) 

for r in tree.iter("root"): 
    ch = r.find("name") 
    r.remove(ch) 
    r.insert(0, ch) 

print(et.tostring(tree).decode("utf-8")) 

Если узлы на самом деле не в отсортированном порядке, и вы хотите, чтобы переставить корней узла по алфавиту:

x = """ 
    <roots> 
    <root> 
     <path>//1.1.1.100/Alex</path> 
     <name>Alex Space</name> 
    </root> 
    <root> 
     <path>//1.1.1.101/Steve</path> 
     <name>Steve Space</name> 
    </root> 
    <root> 
     <path>//1.1.1.150/Bethany</path> 
     <name>Bethanys</name> 
    </root> 
</roots>""" 
import lxml.etree as et 
tree = et.fromstring(x) 

tree[:] = sorted(tree, key=lambda ch: ch.xpath("name/text()")) 

print(et.tostring(tree).decode("utf-8")) 

Который даст вам:

<roots> 
    <root> 
     <path>//1.1.1.100/Alex</path> 
     <name>Alex Space</name> 
    </root> 
    <root> 
     <path>//1.1.1.150/Bethany</path> 
     <name>Bethanys</name> 
    </root> 
    <root> 
     <path>//1.1.1.101/Steve</path> 
     <name>Steve Space</name> 
    </root> 
</roots> 

Вы также можете комбинировать с любым из первых два подхода два также перестроить корень узлов, ставящих имя первым.

+0

Ваше окончательное предложение было тем, что я собирался, спасибо – bzzWomp

+0

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

-1

Попробуйте это:

import xml.etree.ElementTree as ET 


xml="<?xml version='1.0' encoding='UTF-8'?><roots><root><path>//1.1.1.100/Alex</path><name>Alex Space</name></root><root><path>//1.1.1.101/Steve</path><name>Steve Space</name></root><root><path>//1.1.1.150/Bethany</path><name>Bethanys</name></root></roots>" 
oldxml = ET.fromstring(xml) 

names = [] 
for rootobj in oldxml.findall('root'): 
    names.append(rootobj.find('name').text) 

newxml = ET.Element('roots') 
for name in sorted(names): 
    for rootobj in oldxml.findall('root'): 
     if name == rootobj.find('name').text: 
      newxml.append(rootobj) 
ET.dump(oldxml) 
ET.dump(newxml) 

Я читаю из переменной и dumpin его на экране.

Вы можете изменить его, прочитав из файла, и выгрузите его в файл, как вам нужно.

 Смежные вопросы

  • Нет связанных вопросов^_^