使用elementTree编辑和复制xml块

时间:2015-10-13 13:00:35

标签: python xml elementtree

我想编辑以下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>

1 个答案:

答案 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不会将父元素保留在元素中,因此同一元素可以同时在多个树中共存。据我所知,没有强制深度复制的内置方法...... 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例程效率很低,但很简单,无论树有多深,它都能正常工作。