Python中从多层嵌套XML子节点提取标签与文本——递归调用问题
问题描述
需要提取XML块中所有嵌套子节点的标签与文本,编写的Python代码如下,但get_tag_and_text函数的keys_and_values字典无法收集所有内容,仅保留最后一个有效条目:
import xml.etree.ElementTree as ET class MyParser: def __init__(self, xml_block): self.xml_block = xml_block def main(self): tree = ET.ElementTree(ET.fromstring(self.xml_block)) root = tree.getroot() self.get_tag_and_text(root) def get_tag_and_text(self, root): keys_and_values = {} for child in root: if child.text is not None: keys_and_values[child.tag] = child.text self.get_tag_and_text(child)
示例XML
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <abc:random xmlns:abc="http://www.mywebsite.com" schemaVersion="1.2"> <abc:header> <abc:number>8</abc:number> <abc:type>text/xml</abc:type> </abc:header> <abc:body> <abc:d> <abc:purpose>start</abc:purpose> </abc:d> </abc:body> </abc:random>
问题原因
- 每次递归调用
get_tag_and_text时都会新建局部字典keys_and_values,递归完成后该字典不会传递回上层调用,导致只有当前层的临时数据无法累积 - 方法未返回收集到的字典,也未将子节点递归得到的结果合并到当前字典中
- 类方法缩进错误,
main和get_tag_and_text未正确归属到MyParser类内部
修正后的代码
import xml.etree.ElementTree as ET class MyParser: def __init__(self, xml_block): self.xml_block = xml_block def main(self): root = ET.fromstring(self.xml_block) return self.get_tag_and_text(root) def get_tag_and_text(self, element): keys_and_values = {} # 处理当前节点的文本(过滤纯空白内容) if element.text and element.text.strip(): keys_and_values[element.tag] = element.text.strip() # 递归处理子节点并合并结果 for child in element: child_data = self.get_tag_and_text(child) keys_and_values.update(child_data) return keys_and_values
关键修改说明
- 修正类方法缩进,确保
main和get_tag_and_text属于MyParser类 get_tag_and_text返回收集到的字典,每次递归时用update方法将子节点的结果合并到当前字典- 添加纯空白文本过滤逻辑,避免收集无效空值
main方法直接返回最终收集结果,方便外部调用
测试结果
使用示例XML运行修正后的代码:
xml_content = """<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <abc:random xmlns:abc="http://www.mywebsite.com" schemaVersion="1.2"> <abc:header> <abc:number>8</abc:number> <abc:type>text/xml</abc:type> </abc:header> <abc:body> <abc:d> <abc:purpose>start</abc:purpose> </abc:d> </abc:body> </abc:random>""" parser = MyParser(xml_content) result = parser.main() print(result)
输出结果:
{ '{http://www.mywebsite.com}number': '8', '{http://www.mywebsite.com}type': 'text/xml', '{http://www.mywebsite.com}purpose': 'start' }
如果需要去掉命名空间前缀,可添加辅助函数处理:
def strip_namespace(tag): return tag.split('}')[1] if '}' in tag else tag # 在get_tag_and_text中替换tag赋值逻辑: keys_and_values[strip_namespace(element.tag)] = element.text.strip()
处理后输出的键会变成number、type、purpose,更简洁。
内容的提问来源于stack exchange,提问作者pymat
相关产品推荐
相关产品推荐

