2016-10-20 2 views
0

'이름이'인 '루트'태그가 여러 개 있습니다. 'name'요소에 의해 사전 순으로 정렬 된 '루트'블록을 정렬하고 싶습니다. lxml/etree/minidom을 사용해 보았지만 작동시키지 못했습니다 ... 태그 내부의 값을 구문 분석하고 부모 루트 태그를 정렬 할 수 없습니다. 여기 자식 요소별로 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> 

내가 시도 것입니다 :

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

이 시도 : 나는 변수에서 읽고 화면에 dumpin있어

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) 

.

파일에서 읽은 내용을 변경하고 필요에 따라 파일로 덤프 할 수 있습니다.