我可以克隆一个xml节点吗?

时间:2013-02-15 05:42:33

标签: python xml python-3.x deep-copy

Python的新手,对xml更是如此,所以忍受我:)

我有一个现有的xml文件,其结构如下所示。我想克隆匹配<Zone>或我指定的任何<name>.text == "Bill"节点。

我尝试循环并使用elem.append(copy.deepcopy(---)),但最后我添加了添加到循环中的节点 - 不用说它运行了一段时间!

我可以在原地轻松完成此操作,还是必须将所有内容写入另一个文件?我会添加代码,但担心它会被破坏,只会使事情变得复杂!

希望我已经明确了问题。

<DBname>  
    <Level_1>  
        <Zone>  
            <name>Fred</name>  
            <att1>xxx</att1>  
            <att2>yyy</att2>  
        </Zone>  
        <Zone>  
            <name>Bill</name>  
            <att1>111</att1>  
            <att2>222</att2>  
        </Zone>  
        <Zone>  
            <name>Bob</name>  
            <att1>333</att1>  
            <att2>444</att2>  
        </Zone>  
    </Level_1>  
</DBname>  

好的我可能已经找到了解决方案,但欢迎任何评论/改进。

这不起作用。附加的项目填满了“for”循环:

from lxml import etree as ET
import copy

tree = ET.parse(xml_file)
root  = tree.getroot()
for elem in root:
    for source in elem:
        if source.find('name').text == "Bill":
            elem.append(copy.deepcopy(source))

这似乎有效:

from lxml import etree as ET
import copy

tree = ET.parse(xml_file)
root  = tree.getroot()
for elem in root:
    for zone in elem.findall('Zone'):
        if zone.find('name').text == "Bill":
            elem.append(copy.deepcopy(zone))

1 个答案:

答案 0 :(得分:1)

你的第二次尝试看起来是正确的。问题是你在尝试迭代它时修改了一个对象。

for source in elem的情况下,似乎lxml懒惰地遍历子节点,因此在lxml到达结尾之前添加的任何新节点都包含在迭代中。通过使用.findall,您将获得一个新的后代列表,该列表不会受到elem的后续更改的影响。

请注意,您的工作代码现在具有不同的语义;它会找到所有后代Zone标签,而不仅仅是儿童。鉴于您的架构,这可能无关紧要,但这是您已经知道的不需要的额外工作。

您可以通过执行以下操作来修复第一次尝试:

for source in list(elem):

这会创建一个单独的子节点列表,因此对elem的修改是安全的,不会影响循环。

如果你想明确地将循环限制为Zone s:

for source in list(elem.iter('Zone')):