任务是 - 在迭代xml树时删除'当前'节点,保存xml文档并将其提供给第三方应用程序。根据结果将此节点带回树或忘记它。
让我展示一下奇怪之处:</ p>
<test>
<A>
<A1>
<A2>A2</A2>
</A1>
</A>
<B>
<B1>B1</B1>
</B>
<C>C</C>
</test>
这是python代码:
from lxml import etree as ET
tree = ET.parse('t.xml')
delete = False
def print_tree():
print '*' * 5
for node in tree.getiterator():
print node.tag
print '*' * 5
print_tree()
for node in tree.getiterator():
#delete the first node (<A> in our case)
if not delete:
try:
node.getparent().remove(node)
delete = True
except:
pass
print '* ' + node.tag
print_tree()
输出将是这样的:
*****
test
A
A1
A2
B
B1
C
***** <-- these are all elements iterator can reach
* test
* A
* A1
* A2
*****
test
B
B1
C
*****
正如您在删除节点后所看到的那样,迭代器仅转到A分支。
如何让它覆盖树的其余部分?我希望有一个更优雅的解决方案。
答案 0 :(得分:1)
我认为您的代码或环境存在多个问题。
当我运行你的代码(Windows 7x64 32位python 2.7.8)时,我得到以下(与你的不同)输出:
*****
test
A
A1
A2
B
B1
C
*****
* test
* A
* A1
* A2
*****
test
B
B1
C
*****
所以我从你那里获得不同输出的第一个问题可能是环境 - 你的或我的。您使用的是什么版本的python?
你的问题是为什么迭代器不进入树的B部分?好吧,看看你的删除代码,它删除了当前节点,然后你假设迭代器将继续进一步迭代进入树的其余部分 - 即你正在修改当前正在运行的点上的树。这很可能会混淆迭代器,它正在做。
AFAICT remove()方法的描述说'从元素中删除子元素'。您正在尝试使用删除删除“元素”,这就像坐在树枝的末端并在树干附近锯开它。
假设您只想使用迭代器删除A节点,这是有效的(请注意中断 - 进一步迭代没有意义)(还要注意没有try / except):
for node in tree.getiterator():
#delete the first <A> subelement
Anode = node.find("A")
if Anode is not None:
node.remove(Anode)
break
另一个问题可能在于您的代码。你的except语句只包含'pass'来抑制异常 - 这是一个非常狡猾的事情。我的环境中的异常原因是第一次进入for循环,即在根节点测试时,对getparent()的调用正确地返回None,并且无法删除。抑制这样的所有异常并不是解决该问题的可靠方法,因为它还可以抑制任何其他错误,并且无论如何意味着代码中可能存在逻辑错误。
HTH 巴尼