2

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

1 回答 1

1

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

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

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

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

for source in list(elem):

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

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

for source in list(elem.iter('Zone')):
于 2013-03-01T02:14:05.647 回答