这似乎取决于您是使用内置的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例程的效率相当低,但却很直接,并且无论树有多深,它都可以正常工作。
但我怎么能做出选择只考虑duplicateAndAddOne? – Nickpick
你必须遍历每个元素,并提取'name'元素,然后决定如何处理它。尽管如果你能够控制这个XML,那么'Strategy'似乎不适用于该部分;类似于'strategy ='duplicate''属性的'DataFrame'似乎在语义上更一致... –