2013-02-15 54 views
2

一位新手到Python,甚至更多的XML以便与我携手:)我可以克隆一个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> 

好吧,我可能已经制定了解决方案,但任何意见/改进,深受欢迎。

这不起作用。所附的项目的东西了 “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

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

for source in elem的情况下,看起来lxml懒惰地迭代子节点,所以在迭代中包括在lxml之前添加的任何新节点到达末端。通过使用.findall,您会得到一个不受后续elem更改影响的后代列表。

请注意,您的工作代码现在有不同的语义;它会发现全部后裔Zone标签,而不仅仅是儿童。考虑到你的模式,这可能并不重要,但它是你已经知道你不需要的额外工作。

你可以做修复的第一次尝试:

for source in list(elem): 

这将创建子节点的单独列表,所以修改elem是安全的,不会影响环路。

如果你想明确地限制循环只是Zone S:

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

感谢伊布 - 为解释和额外的代码提示为好。我在学! – RustyC 2013-03-01 03:42:07

相关问题