我一直在使用python和ElementTree来操作相当大的xml文件并取得了成功。我发现我很难删除多个元素,特别是当它们是root的子元素时。如果我有4个元素编号1-4,则只使用“for elem in root”子句删除1和3。
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<CrossDEV culture-info="en-US" platform-version="2.40.8" product-version="2.40.8">
<MyStuff.Interface.Common.Objects.ActionItem ImportMode="Default">
<TargetObjectKey>FOOSTUFF1</TargetObjectKey>
</MyStuff.Interface.Common.Objects.ActionItem>
<MyStuff.Interface.Common.Objects.ActionItem ImportMode="Default">
<TargetObjectKey>FOOSTUFF2</TargetObjectKey>
</MyStuff.Interface.Common.Objects.ActionItem>
<MyStuff.Interface.Common.Objects.ActionItem ImportMode="Default">
<TargetObjectKey>FOOSTUFF3</TargetObjectKey>
</MyStuff.Interface.Common.Objects.ActionItem>
<MyStuff.Interface.Common.Objects.ActionItem ImportMode="Default">
<TargetObjectKey>FOOSTUFF4</TargetObjectKey>
</MyStuff.Interface.Common.Objects.ActionItem>
</CrossDEV>
代码:
def RemoveElementActionItem():
sTag = 'SourceObjectKey'
sTag2 = 'TargetObjectKey'
sPattern = 'CHE-ZUG'
r=0
e=0
global myroot
if myroot is not None:
print ('Root:', myroot)
for elem in myroot:
e+=1
print ('Elem:',e, elem)
aRemove = True
bRemove = True
o = elem.find(sTag)
if o is not None and o.text.find(sPattern,0) > -1:
aRemove = False
p = elem.find(sTag2)
if o is not None and o.text.find(sPattern,0) > -1:
bRemove = False
if bRemove and aRemove:
myroot.remove(elem)
r+=1
print ('Removed:', myroot, elem)
else:
print (' Keep:', myroot, elem, o , p, aRemove, bRemove)
return r
在上面的代码中,我正在寻找孙子的特定文本值。我拼凑了一个简单的xml文件,每个ActionItem都无法通过测试,因此应该将其删除。相反,只有4个中的2个被删除。
我的猜测是,当删除列表中的第一个时,地址会发生变化,以便跳过第二个地址。接下来,第三个被删除,列表再次向前移动。
因为在这个简单的情况下应该删除所有4个元素,有什么更好的方法来构造我的代码?如果可以的话,我宁愿坚持使用相同的库,因为我已经投入了大量的时间并且尚未探索lxml或其他库。
注意,我一直在玩不同的方法来定位根对象(myroot)。我把它作为一个参数,一个返回值,在这里作为全局。我各方面都有相同的结果。
答案 0 :(得分:0)
code.py :
import sys
from xml.etree import ElementTree as ET
XML_STR = """\
<?xml version="1.0" encoding="utf-8"?>
<RootNode>
<ChildNode DummyIndex="0">
<GrandChildNode DummyIndex="0">GrandChildText</GrandChildNode>
<GrandChildNode_ToRemove DummyIndex="0">GrandChildText</GrandChildNode_ToRemove>
</ChildNode>
<ChildNode DummyIndex="1">
<GrandChildNode_ToDelete DummyIndex="0">GrandChildText</GrandChildNode_ToDelete>
<GrandChildNode_ToRemove DummyIndex="0">GrandChildText</GrandChildNode_ToRemove>
</ChildNode>
<ChildNode DummyIndex="2">
<GrandChildNode DummyIndex="0">GrandChildText</GrandChildNode>
<GrandChildNode_ToDelete DummyIndex="0">GrandChildText</GrandChildNode_ToDelete>
<GrandChildNode_ToRemove DummyIndex="0">GrandChildText</GrandChildNode_ToRemove>
</ChildNode>
<ChildNode DummyIndex="3">
<GrandChildNode_ToRemove DummyIndex="0">GrandChildText</GrandChildNode_ToRemove>
<GrandChildNode_ToRemove DummyIndex="1">GrandChildText</GrandChildNode_ToRemove>
</ChildNode>
<ChildNode DummyIndex="4">
<GrandChildNode_ToDelete DummyIndex="0">GrandChildText</GrandChildNode_ToDelete>
<GrandChildNode_ToRemove DummyIndex="0">GrandChildText</GrandChildNode_ToRemove>
<GrandChildNode_ToDelete DummyIndex="1">GrandChildText</GrandChildNode_ToDelete>
</ChildNode>
<ChildNode DummyIndex="5">
<GrandChildNode_ToDelete DummyIndex="0">GrandChildText</GrandChildNode_ToDelete>
</ChildNode>
<ChildNode DummyIndex="6">
<GrandChildNode DummyIndex="0">GrandChildText</GrandChildNode>
<GrandChildNode_ToRemove DummyIndex="0">GrandChildText</GrandChildNode_ToRemove>
</ChildNode>
<ChildNode DummyIndex="7">
<GrandChildNode_ToDelete DummyIndex="0">GrandChildText</GrandChildNode_ToDelete>
<GrandChildNode_ToRemove DummyIndex="0">____OTHERTEXT____</GrandChildNode_ToRemove>
<GrandChildNode DummyIndex="0">GrandChildText</GrandChildNode>
</ChildNode>
<ChildNode DummyIndex="8"/>
</RootNode>
"""
REMOVE_GRANDCHILD_TAGS = ["GrandChildNode_ToDelete", "GrandChildNode_ToRemove"]
REMOVE_GRANDCHILD_TEXT = "Child"
def is_node_subject_to_delete(node):
removable_child_nodes_count = 0
for remove_tag in REMOVE_GRANDCHILD_TAGS:
for child_node in node.findall(remove_tag):
if REMOVE_GRANDCHILD_TEXT in child_node.text:
removable_child_nodes_count += 1
break
return removable_child_nodes_count == len(REMOVE_GRANDCHILD_TAGS)
def main():
print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
#print(XML_STR)
root_node = ET.fromstring(XML_STR)
print("Root node has {:d} children\n".format(len(root_node.findall("ChildNode"))))
to_remove_child_nodes = list()
for child_node in root_node:
if is_node_subject_to_delete(child_node):
to_remove_child_nodes.append(child_node)
print("Removing nodes:")
for to_remove_child_node in to_remove_child_nodes:
print("\n Tag: {}\n Text: {}\n Attrs: {}".format(to_remove_child_node.tag, to_remove_child_node.text.strip(), to_remove_child_node.items()))
root_node.remove(to_remove_child_node)
print("\nRoot node has {:d} children\n".format(len(root_node.findall("ChildNode"))))
if __name__ == "__main__":
main()
备注强>:
XML_STR
:示例 xml (也可以放在单独的文件中)
NULL
,空白或只是由不可打印的字符组成) REMOVE_GRANDCHILD_TAGS
- 标记名称列表,这样,如果(根子项)节点的子项与列表中的所有标记匹配,则可以将其删除 - 替换{ {1}}和sTag
- (请查看下面的sTag2
备注),如果需要其他标记(例如is_node_subject_to_delete
),则可以将其添加到列表(不需要其他副本 / 粘贴操作)
GrandChildNode_ToErase
- 上一项的2 nd 条件:如果节点文本名称包含该文本(&#34; Child < / em>&#34;) - 如果满足两个条件,则节点 delete 能够REMOVE_GRANDCHILD_TEXT
- 检查是否可以删除参数(is_node_subject_to_delete(node)
- root child):
node
)中 - 而不是复制代码,则代码为REMOVE_GRANDCHILD_TAGS
(最外层)循环for
- 一般包装函数
<强>输出强>:
main
答案 1 :(得分:0)
虽然这里的其他答案非常有用,但我个人却无法使用它,因为我无法让每个孩子都有相同的名字。相反,我最终遍历Element Tree的方式是使用while循环,在这种情况下,如果必须删除孩子,我会减小end变量(而不是增加计数器)。
通过减少最终目标,可以避免出现“越界”错误
下面是一个为简单起见而遍历字符串的示例:
i = 0
word = 'Python'
end = len(word)
while i < end:
letter = word[i]
if letter == 'h':
word = word.replace(letter, '')
end-=1
continue
print('Current Letter :' + letter)
i+=1
如果将此应用于元素树,则代码看起来或多或少相同,除了使用replace
代替root.remove(child)
,其中{{1 }}
我希望这可以帮助某人。感谢您的阅读。