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))
答案 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')):