2014-09-27 220 views
2

我有一個非常大的XML,我需要從刪除一些特定的節點在另一個節點。 例如我有一個列表,其中包含應該出現在xml中的節點的名稱。因此,除了這些節點之外,父節點中的所有其他節點都應該被刪除並寫入新的xml文件。Python:在xml中,如何刪除父節點中的節點

我只需要刪除節點,即「實例」,其中第一個「數據」元素不等於出現在我的名單,我會提供一個值。其餘的xml信息,即'描述','符號'標籤不應該被打擾。

假設:我已經解析了應該從外部文件讀取到python列表變量的數據。

DOM或SAX任何人都可以。但我相信DOM非常快。 對於任何BIF的可用或邏輯的任何提示對我來說也是很好的。

注意:我是Python新手。所以請評論我的代碼中是否有任何錯誤。

我下面的代碼:

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

向我們展示您的工作? – 2014-09-27 19:41:42

+0

@Vivek:我用我的代碼更新了問題的詳細信息。用我的代碼,所有的xml標籤都被替換爲「ns0:」。我不知道爲什麼會發生這種情況。 – manty 2014-09-27 20:11:28

+0

'File.txt'的內容是什麼? – Yoel 2014-09-27 20:29:11

回答

2

您是數點的困惑。

第一個,您提供的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> 

,如果您擔心速度,可以考慮使用cElementTree代替ElementTree

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

,你需要一個名稱分配給ET.parse方法的結果,或者你就沒有辦法以後引用它:

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

,現在你需要找到樹的根你會發現所有的樹的Instance元素之前:

>>> 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') 

現在,你需要找到Instance元件,其Data值表明,應該刪除Instance元素:

第五個,您需要檢查文本是否是第一個Data元素在你的門將名單,並第六,你從rootremove你的元素(或任何父恰好是),而不是從instances

>>> 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」。當我在'remove'語句之後再添加一個分隔符時,這個錯誤消失了,然後新的xml按照預期正常打印。但仍然是我的原始xml給了ValueError.Any想法可能是什麼原因? – manty 2014-09-28 11:09:59

+0

@manty確保你的'else'語句直接落在'for'語句下,而* not *語句落在'if'語句下。 'else'語句只應在所有'Data'元素運行完畢後才運行。它屬於'for'循環。如果你用'if'語句排列它的縮進,你可能會嘗試刪除一個'Instance'元素兩次,並會得到你提到的錯誤。 – 2014-09-28 11:35:43

+0

@manty請注意,我也稍微修改了代碼,因爲您在上面的註釋中指出,您只希望檢查第一個'Data'元素的值與'keeper_list'對應的值。如果我的答案幫助您解決了問題,請考慮[接受它](http://meta.stackexchange.com/a/5235)作爲正確答案。 – 2014-09-28 11:46:05