2014-09-27 4 views
2

나는 꽤 큰 xml을 가지고 있는데, 다른 노드 내의 특정 노드를 삭제해야합니다.. 예 : xml에 존재해야하는 노드의 이름을 포함하는 목록이 있습니다. 따라서 이들 노드를 제외하고는 상위 노드 내의 모든 다른 노드를 삭제하고 새 XML 파일에 작성해야합니다.Python : xml에서 부모 노드 내의 노드를 삭제하는 방법

나는 단지 삭제해야 노드 최초의 '데이터'요소는 내가 제공하는 것입니다 내 목록에 값이 동일하지 않은 즉 '인스턴스'. 나머지 XML 정보 즉 '설명', '기호'태그는 방해 받아서는 안됩니다.

가정 : 외부 파일에서 읽어야하는 데이터를 파이썬 목록 변수로 구문 분석했습니다.

누구나 나를 위해 괜찮습니다. 그러나 나는 DOM이 매우 빠르다고 믿습니다. BIF의 사용 가능 또는 로직에 대한 힌트도 나에게 도움이 될 것입니다.

참고 : 저는 Python을 처음 사용합니다. 그래서 내 코드에서 어떤 것이 잘못되었다고 말하십시오. 아래

내 코드 :

<?xml version='1.0' encoding='UTF-8'?> 
<Identification> 
<Description ID="12">Some text</Description> 
</Identification> 
<Symbols> 
    <Name Width="1">abc</Name> 
    <Name Width="2">def</Name> 
</Symbols> 

<Instance RowRef="A"> 
    <DataSet> 
    <Data>12345678</Data> 
    </DataSet> 
    <DataSet> 
    <Data>abcd</Data> 
    </DataSet> 
    <DataSet> 
    <Data>abcd</Data> 
    </DataSet> 
</Instance> 
<Instance RowRef="B"> 
    <DataSet> 
    <Data>87654321</Data> 
    </DataSet> 
    <DataSet> 
    <Data>abcd</Data> 
    </DataSet> 
    <DataSet> 
    <Data>abcd</Data> 
    </DataSet> 
</Instance> 
<Instance RowRef="C"> 
    <DataSet> 
    <Data>06354237/Data> 
    </DataSet> 
    <DataSet> 
    <Data>abcd</Data> 
    </DataSet> 
    <DataSet> 
    <Data>abcd</Data> 
    </DataSet> 

+1

작품보기 –

+0

@Vivek : 내 코드로 질문 세부 사항을 업데이트했습니다. 내 코드에서 모든 XML 태그가 "ns0 :"으로 바뀌고 있습니다. 왜 이런 일이 일어나고 있는지 모르겠습니다. – manty

+0

'File.txt'의 내용은 무엇입니까? – Yoel

답변

2

당신은 점의 수에 혼란 : 아래

from xml.etree.ElementTree import ElementTree 
tree = ElementTree() 
tree.parse('Test.xml') 

file = open("File.txt") 

list = [] 

for lines in file: 
    list.append(lines) 

Instance = tree.findall('Instance') 
for i in Instance: 
    while (i != list[i]): 
     Instance.remove(i) 

tree.write('new.xml') 

샘플 XML 파일입니다.

처음으로, 제공 한 XML에는 루트 태그가 없습니다.XML 파일이 같은 뭔가 더 (Root가 어떤 태그로 대체 될 수있는 필요) 보일 것입니다 : 당신이 속도에 대해 우려하는 경우,

<?xml version='1.0' encoding='UTF-8'?> 
<Root> 
<Identification> 
<Description ID="12">Some text</Description> 
</Identification> 
<Symbols> 
    <Name Width="1">abc</Name> 
    <Name Width="2">def</Name> 
</Symbols> 

<Instance RowRef="A"> 
    <DataSet> 
    <Data>12345678</Data> 
    </DataSet> 
    <DataSet> 
    <Data>abcd</Data> 
    </DataSet> 
    <DataSet> 
    <Data>abcd</Data> 
    </DataSet> 
</Instance> 
<Instance RowRef="B"> 
    <DataSet> 
    <Data>87654321</Data> 
    </DataSet> 
    <DataSet> 
    <Data>abcd</Data> 
    </DataSet> 
    <DataSet> 
    <Data>abcd</Data> 
    </DataSet> 
</Instance> 
<Instance RowRef="C"> 
    <DataSet> 
    <Data>06354237</Data> 
    </DataSet> 
    <DataSet> 
    <Data>abcd</Data> 
    </DataSet> 
    <DataSet> 
    <Data>abcd</Data> 
    </DataSet> 
</Instance> 
</Root> 

둘째ElementTree 대신 cElementTree을 사용하는 것이 좋습니다 :

>>> import xml.etree.cElementTree as ET # use cElementTree for faster processing 

셋째, 당신은 ET.parse 방법의 결과에 이름을 할당해야하거나 나중에 참조 할 방법이 없습니다 :

>>> root = tree.getroot() # now get the root 
>>> keeper_data = ['06354237', '87654321'] # your list that you will apparently get from a file? 
>>> instances = root.findall('Instance') 

지금 당신이 그 Data 값을 나타냅니다 Instance 요소를 찾을 필요가 : 3,691,363,210

>>> tree = ET.parse('Test.xml') 

넷째, 지금 당신은 당신이 그 나무의 모든 Instance 요소를 찾기 전에 트리의 루트를 찾을 필요 Instance 요소를 삭제해야합니다 :

제 5의을 삭제하려면 먼저,613,210 요소는 골키퍼 목록에 있고, 는 여섯 번째, 당신은 root에서 요소를 remove (또는 부모가 될 일이 무엇이든) instances에서와 NOT :

>>> for instance in instances: 
     data1 = instance.find('./DataSet/Data') 
     if data1.text not in keeper_data: 
      # NOTE WELL: I remove from the root (not the instance) below! 
      root.remove(instance) 

이제 새 XML 파일에 쓰기 :

>>> tree.write('New.xml') 

귀하의 결과 XML 파일은 다음과 같습니다

<Root> 
<Identification> 
    <Description ID="12">Some text</Description> 
</Identification> 
<Symbols> 
    <Name Width="1">abc</Name> 
    <Name Width="2">def</Name> 
</Symbols> 
<Instance RowRef="B"> 
    <DataSet> 
    <Data>87654321</Data> 
    </DataSet> 
    <DataSet> 
    <Data>abcd</Data> 
    </DataSet> 
    <DataSet> 
    <Data>abcd</Data> 
    </DataSet> 
    </Instance> 
    <Instance RowRef="C"> 
    <DataSet> 
    <Data>06354237</Data> 
    </DataSet> 
    <DataSet> 
    <Data>abcd</Data> 
    </DataSet> 
    <DataSet> 
    <Data>abcd</Data> 
    </DataSet> 
    </Instance> 
</Root> 

하지 않음 e 값이 12345678이고 다른 keeper_data 요소가없는 데이터 요소가있는 인스턴스가 생략되었음을 나타냅니다.

+0

네, 맞았는데, 제 질문에서 비교할 '데이터'값을 언급하지 않았습니다. 그러나 당신은 그것을 바로 추측했습니다, 그것은 최초의 '데이터'요소였습니다. 그러나이 코드는 나에게 "ValueError : list.remove (x) : x not in list"와 같은 에러를 주었다. 이 오류는 '제거'문 다음에 한 번 더 휴식을 추가 한 다음 새로운 xml이 expected.But으로 인쇄하면 괜찮습니다.하지만 여전히 원본 xml은 ValueError.Any 아이디어를 제공합니다. 원인은 무엇입니까? – manty

+0

@manty'else' 문이'for' 문 바로 아래에 있고 * if *가'if' 문 아래에 있어야합니다. 'else' 문은 모든'Data' 엘리먼트가 실행 된 후에 만 ​​실행되어야합니다. 'for' 루프에 속합니다. 'if' 문으로 들여 쓰기를 정렬하면'Instance' 요소를 두 번 제거하려고 시도하고 언급 한 오류가 발생합니다. –

+0

@manty 또한 위의 코멘트에서 keeper_list에 대해 첫 번째'Data' 요소의 값만 확인하고 싶다고 지정 했으므로 코드를 약간 수정했습니다. 내 대답이 당신의 문제를 해결하는 데 도움이 되었다면, [받아들이 기] (http://meta.stackexchange.com/a/5235)를 정답으로 생각하십시오. –

관련 문제