2015-08-17 30 views
0

任務是 - 在通過xml樹進行迭代時刪除'當前'節點,保存xml文檔並將其提供給第三方應用程序。根據結果​​將此節點返回到樹或者忘記它。lxml的etree迭代器的奇怪行爲

讓我展示了怪胎:

<test> 
    <A> 
    <A1> 
     <A2>A2</A2> 
    </A1> 
    </A> 
    <B> 
    <B1>B1</B1> 
    </B> 
    <C>C</C> 
</test> 

這裏的Python代碼:

from lxml import etree as ET 

tree = ET.parse('t.xml') 

delete = False 

def print_tree(): 
    print '*' * 5 
    for node in tree.getiterator(): 
     print node.tag 
    print '*' * 5 

print_tree() 

for node in tree.getiterator(): 
    #delete the first node (<A> in our case) 
    if not delete: 
     try: 
      node.getparent().remove(node) 
      delete = True 
     except: 
      pass 

    print '* ' + node.tag 

print_tree() 

輸出將是這樣的:

***** 
test 
A 
A1 
A2 
B 
B1 
C 
***** <-- these are all elements iterator can reach 
* test 
* A 
* A1 
* A2 
***** 
test 
B 
B1 
C 
***** 

正如你可以刪除後見迭代器的節點只進入A分支。

我該如何使它覆蓋樹的其餘部分?我會欣賞一個更優雅的解決方案。

+0

您的xml非常大嗎?我認爲它不建議在迭代時嘗試更改xml的結構。 –

回答

1

我認爲您的代碼或環境存在多個問題。

當我運行的代碼(的Windows 7x64 32位的Python 2.7.8)我得到以下(與你的不同)輸出:

***** 
test 
A 
A1 
A2 
B 
B1 
C 
***** 
* test 
* A 
* A1 
* A2 
***** 
test 
B 
B1 
C 
***** 

所以我的這第一個問題得到不同的輸出從您的可能是由於環境 - 你或我的。你使用的是什麼版本的Python?

你的問題是爲什麼迭代器不進入樹的B部分?那麼,看看你的刪除代碼,它會刪除當前節點,然後你假設迭代器將進一步迭代到樹的其餘部分 - 即你正在修改目前所在點上的樹。這很可能會混淆迭代器,並且它正在做。

AFAICT remove()方法的描述說'從元素中刪除子元素'。您試圖使用刪除來刪除「元素」,就像坐在樹枝的末端並在靠近樹幹處切割。

假設你只想使用迭代器,這個工作(注意休息 - 在進一步的迭代是沒有意義的)來刪除一個節點(也注意到/除了缺席的情況下嘗試的):

for node in tree.getiterator(): 
    #delete the first <A> subelement 
    Anode = node.find("A") 
    if Anode is not None: 
     node.remove(Anode) 
     break 

的其他問題可能與您的代碼。你的除了'通'之外的聲明是壓制一個異常 - 這是一個非常不好的事情。在我的環境中,異常的原因是第一次進入for循環,即在根節點測試中,對getparent()的調用正確返回None,並且無法刪除。抑制這樣的所有異常對於這個問題並不是一個可靠的解決方案,因爲它也可以抑制任何其他錯誤,無論如何意味着代碼中可能存在邏輯錯誤。

HTH barny

+0

感謝您的全面回答。有兩件事:輸出的差異是因爲我編輯了帖子並沒有解決所有問題(現在一切都應該沒問題)。其次 - 實際上我想嘗試刪除文檔中的每個節點,因此查找和刪除技巧將無法工作。據我瞭解 - 爲了保持迭代器運行,我可以看到下一個分支,但不是我(迭代器)當前坐的那個分支? –

+0

在迭代器中刪除/修改可能有風險。如果你想刪除所有節點,爲什麼不創建一個新的空樹?或者搜索stackoverflow,看看例子中的答案像http://stackoverflow.com/questions/14051422/how-do-i-remove-a-node-in-xml-using-elementtree-in-python – barny

+0

我的意思是我'我會逐一刪除它們(其中一些最終會保留)。發現這個人在這裏http://stackoverflow.com/questions/19419754/how-to-remove-a-node-inside-an-iterator-in-python-xml-etree-elementree想做的事情很相似,他認爲這種方法運作良好。我只是意識到他不需要活着的迭代器,忘記它。 –