2015-10-13 128 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'似乎在语义上更一致... –