xml.etree.ElementTree 插入子节点的子节点创建无限循环 Python
xml.etree.ElementTree insert into child of child node creating infinity loop Python
我试图在大型 XML 文档(~2000 行)中的子节点的特定子节点插入一个元素,下面是我的代码:
import xml.etree.cElementTree as ET
class Kapow_commands:
tree = ET.parse('location/of/xml/file')
root = tree.getroot()
seq_id = 39
def __init__(self):
pass
def append(self, block):
node_num=0
for node in Kapow_commands.root[13][1]:
node_num=node_num+1
if node.get('class') == 'End':
node.attrib['id'] = str(Kapow_commands.seq_id + 1)
print(node.attrib)
print(node_num)
Kapow_commands.root[13][1].insert(node_num -1, block)
block = ET.Element("test")
Kapow_commands().append(block)
此代码在特定节点扫描 XML 文件以获得 class = 'End',然后将 1 添加到该元素 ID 并在它之前插入另一个元素。但是,当我 运行 这似乎创建了一个无限循环,因为它不会停止在此位置插入元素。有谁知道为什么会这样?或者关于如何在所需位置正确插入此元素的任何想法?
我遇到了类似的问题。
解决方案是将要附加的元素的初始化放在循环中。
所以在你的情况下,我会传递一个名称作为参数,代码如下所示:
def append(self, blockName): # here comes the name
node_num=0
for node in Kapow_commands.root[13][1]:
block = ET.Element(name) # and there goes the init
node_num=node_num+1
if node.get('class') == 'End':
node.attrib['id'] = str(Kapow_commands.seq_id + 1)
print(node.attrib)
print(node_num)
Kapow_commands.root[13][1].insert(node_num -1, block)
对我来说,它成功了。不幸的是,我不知道这个魔法背后的原因。
修正
如您评论中所述,在插入新元素后插入 break
语句可解决无限循环问题。
为什么代码会产生死循环
至于为什么会出现无限循环,我们需要了解在python中调用for循环时会发生什么。从 docs 我们看到 for 循环在您的可迭代对象上创建了一个迭代器,在本例中为 Kapow_commands.root[13][1]
,当我们跳出它、序列为空或迭代器引发时终止StopIteration 异常。实际上,如果我们将 for node in Kapow_commands.root[13][1]:
展开,我们会得到类似于
的结果
iterator = iter(Kapow_commands.root[13][1])
while True:
try:
node = iterator.__next__()
# Body of for loop
except StopIteration:
break
这就是神奇的地方。让我们用 'End' End Node
的 class 调用节点。如果我们当前的节点是End Node
,我们执行Kapow_commands.root[13][1].insert(node_num -1, block)
。这会将 block
插入到 我们可迭代对象 中的当前位置,这意味着可迭代对象中的下一项再次变为 End Node
。在 for 循环的下一次迭代中,iterator.__next__()
给我们 End Node
并且我们回到开始的地方,产生一个无限循环。
我试图在大型 XML 文档(~2000 行)中的子节点的特定子节点插入一个元素,下面是我的代码:
import xml.etree.cElementTree as ET
class Kapow_commands:
tree = ET.parse('location/of/xml/file')
root = tree.getroot()
seq_id = 39
def __init__(self):
pass
def append(self, block):
node_num=0
for node in Kapow_commands.root[13][1]:
node_num=node_num+1
if node.get('class') == 'End':
node.attrib['id'] = str(Kapow_commands.seq_id + 1)
print(node.attrib)
print(node_num)
Kapow_commands.root[13][1].insert(node_num -1, block)
block = ET.Element("test")
Kapow_commands().append(block)
此代码在特定节点扫描 XML 文件以获得 class = 'End',然后将 1 添加到该元素 ID 并在它之前插入另一个元素。但是,当我 运行 这似乎创建了一个无限循环,因为它不会停止在此位置插入元素。有谁知道为什么会这样?或者关于如何在所需位置正确插入此元素的任何想法?
我遇到了类似的问题。
解决方案是将要附加的元素的初始化放在循环中。
所以在你的情况下,我会传递一个名称作为参数,代码如下所示:
def append(self, blockName): # here comes the name
node_num=0
for node in Kapow_commands.root[13][1]:
block = ET.Element(name) # and there goes the init
node_num=node_num+1
if node.get('class') == 'End':
node.attrib['id'] = str(Kapow_commands.seq_id + 1)
print(node.attrib)
print(node_num)
Kapow_commands.root[13][1].insert(node_num -1, block)
对我来说,它成功了。不幸的是,我不知道这个魔法背后的原因。
修正
如您评论中所述,在插入新元素后插入 break
语句可解决无限循环问题。
为什么代码会产生死循环
至于为什么会出现无限循环,我们需要了解在python中调用for循环时会发生什么。从 docs 我们看到 for 循环在您的可迭代对象上创建了一个迭代器,在本例中为 Kapow_commands.root[13][1]
,当我们跳出它、序列为空或迭代器引发时终止StopIteration 异常。实际上,如果我们将 for node in Kapow_commands.root[13][1]:
展开,我们会得到类似于
iterator = iter(Kapow_commands.root[13][1])
while True:
try:
node = iterator.__next__()
# Body of for loop
except StopIteration:
break
这就是神奇的地方。让我们用 'End' End Node
的 class 调用节点。如果我们当前的节点是End Node
,我们执行Kapow_commands.root[13][1].insert(node_num -1, block)
。这会将 block
插入到 我们可迭代对象 中的当前位置,这意味着可迭代对象中的下一项再次变为 End Node
。在 for 循环的下一次迭代中,iterator.__next__()
给我们 End Node
并且我们回到开始的地方,产生一个无限循环。