Skip to main content
 首页 » 编程设计

python之我可以就地克隆 xml 节点吗

2025年05月04日14zfyouxi

对 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)) 

请您参考如下方法:

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

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

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

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

for source in list(elem): 

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

如果您想明确地将循环限制在 Zone 中:

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