【问题标题】:Can I clone an xml node in place?我可以克隆一个 xml 节点吗?
【发布时间】:2013-02-15 05:42:32
【问题描述】:

Python 新手,xml 新手更是如此,请多多包涵:)

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

我尝试循环并使用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>  

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

这不起作用。附加项填充了“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))

【问题讨论】:

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


    【解决方案1】:

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

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

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

    您可以通过以下方式修复第一次尝试:

    for source in list(elem):
    

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

    如果您想明确地将循环限制为 Zones:

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

    【讨论】:

    • 感谢 Eevee - 提供解释和额外的代码提示。我在学习!
    猜你喜欢
    • 2016-08-31
    • 1970-01-01
    • 2016-02-19
    • 1970-01-01
    • 2015-03-09
    • 1970-01-01
    • 2011-09-30
    • 2022-06-20
    • 1970-01-01
    相关资源
    最近更新 更多