2015-10-13 44 views
1

我想編輯下面的XML,如下所示:'duplicateAndAddOne'塊應該被複制(名稱更改爲'newElements'),並將其中的所有項目加1。理想情況下,它的元素不應該單獨閱讀,但它應該作爲一個批處理,因爲會有很多項目。使用elementTree編輯和複製xml塊

<?xml version="1.0"?> 
<data> 
    <Strategy name="duplicateAndAddOne"> 
     <datapoint1>7</datapoint1> 
     <datapoint2>9</datapoint2> 
    </Strategy> 
    <Strategy name="leaveMeAlone"> 
     <datapoint1>22</datapoint1> 
     <datapoint2>23</datapoint2> 
    </Strategy> 
</data> 

回答

1

這似乎取決於您是使用內置的ElementTree還是lxml。

隨着LXML,你應該能夠使用copy

from lxml import etree 
e = etree.Element('root') 
etree.SubElement(e, 'child1') 
etree.SubElement(e, 'child2') 

from copy import copy 
f = copy(e) 
f[0].tag = 'newchild1' 
etree.dump(e) 
<root> 
    <child1/> 
    <child2/> 
</root> 

etree.dump(f) 
<root> 
    <newchild1/> 
    <child2/> 
</root> 

你可以看到,新的樹實際上是從舊的分離;這是因爲lxml將父元素存儲在元素中,因此不能重用它們 - 必須爲每個子元素創建新元素。

ElementTree不會將元素保留在元素中,因此同一元素可能同時在多個樹中共存。據我所知,沒有內置的方法來強制進行深度複製... deepcopyelement.copy()兩者的作用與copy完全相同 - 它們複製節點,但將其從原始節點連接到子節點。所以對副本的更改會改變原來的 - 不是你想要的。

我發現使它正常工作的最簡單方法是簡單地序列化爲一個字符串,然後再反序列化它。這迫使全新的元素被創建。這很慢 - 但它也一直有效。比較下列方法:

import xml.etree.ElementTree as etree 
e = Element('root') 
etree.SubElement(e, 'child1') 
etree.SubElement(e, 'child2') 

#f = copy(e) 
#f[0].tag = 'newchild1' 
# If you do the above, the first child of e will also be 'newchild1' 
# So that won't work. 

# Simple method, slow but complete 
In [194]: %timeit f = etree.fromstring(etree.tostring(e)) 
10000 loops, best of 3: 71.8 µs per loop 

# Faster method, but you must implement the recursion - this only 
# looks at a single level. 
In [195]: %%timeit 
    .....: f = etree.Element('newparent') 
    .....: f.extend([x.copy() for x in e]) 
    .....: 
100000 loops, best of 3: 9.49 µs per loop 

這個底部方法確實創建了一級子級的副本,比第一個版本快很多。但是,這隻適用於單層嵌套;如果其中任何一個有孩子,那麼你必須自己下載並複製這些內容。您可能可以編寫遞歸副本,而且速度可能更快;我做過這些的地方沒有對性能敏感,所以我沒有在我的代碼中感到困擾。 tostring/fromstring例程的效率相當低,但卻很直接,並且無論樹有多深,它都可以正常工作。

+0

但我怎麼能做出選擇只考慮duplicateAndAddOne? – Nickpick

+0

你必須遍歷每個元素,並提取'name'元素,然後決定如何處理它。儘管如果你能夠控制這個XML,那麼'Strategy'似乎不適用於該部分;類似於'strategy ='duplicate''屬性的'DataFrame'似乎在語義上更一致... –