我想编辑以下XML,如下所示:'duplicateAndAddOne'块应该重复(名称更改为'newElements')并且其中的所有项目都加1。理想情况下,其中的元素不应单独读取,但应该作为批处理完成,因为会有很多项目。
<?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>
答案 0 :(得分: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不会将父元素保留在元素中,因此同一元素可以同时在多个树中共存。据我所知,没有强制深度复制的内置方法...... deepcopy
和element.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例程效率很低,但很简单,无论树有多深,它都能正常工作。