使用ElementTree与BeautifulSoup按标签层级解析XML并转字典的方法
解答你的XML解析问题
一、完善XML转字典的代码
先帮你补全并优化现有代码——你提到的val函数应该是用来处理DrugBank XML的命名空间,我把这部分逻辑整合进去,同时实现完整的XML转字典功能:
import xml.etree.ElementTree as ET import glob import pprint # 定义DrugBank XML的命名空间常量 DRUGBANK_NS = "{http://www.drugbank.ca}" def xml_to_dict(element): """递归将XML元素转换为嵌套字典结构""" result = {} # 处理元素的属性 if element.attrib: result["@attributes"] = element.attrib # 处理子元素 children = list(element) if children: child_map = {} for child in children: # 去掉命名空间前缀,让键名更简洁 child_key = child.tag.replace(DRUGBANK_NS, "") child_value = xml_to_dict(child) # 处理重复标签(比如多个<synonym>),自动转为列表 if child_key in child_map: if not isinstance(child_map[child_key], list): child_map[child_key] = [child_map[child_key]] child_map[child_key].append(child_value) else: child_map[child_key] = child_value result.update(child_map) # 处理元素的文本内容(无子元素时) elif element.text and element.text.strip(): result = element.text.strip() return result # 遍历所有output开头的本地文件(存储的XML内容) for file_path in glob.glob('output*txt'): tree = ET.parse(file_path) root = tree.getroot() drug_data_dict = xml_to_dict(root) # 打印格式化后的字典结果 pprint.pprint(drug_data_dict)
这段代码的核心逻辑:
- 统一处理DrugBank的命名空间,避免字典键名带冗长前缀
- 递归遍历XML节点,自动处理属性、子元素和文本内容
- 针对重复标签(如药物别名、靶点)自动转为列表,保证数据结构合理
二、按标签层级数量解析的实现
不管是ElementTree还是BeautifulSoup,都可以轻松实现按层级解析,核心思路是跟踪当前节点的层级深度,当达到目标层级时提取节点。下面分别给出两种库的实现方式:
用ElementTree按层级解析
可以通过递归遍历+层级计数,或者迭代式队列跟踪的方式实现:
# 递归方式:提取指定层级的所有元素 def get_elements_by_level(element, target_level, current_level=0): if current_level == target_level: yield element for child in element: yield from get_elements_by_level(child, target_level, current_level + 1) # 示例:提取第2层级的元素(根节点为第0层) root = tree.getroot() for elem in get_elements_by_level(root, 2): print(f"标签名:{elem.tag.replace(DRUGBANK_NS, '')},内容:{elem.text.strip()}")
用BeautifulSoup按层级解析
可以结合递归调用或自定义过滤器来实现层级提取:
from bs4 import BeautifulSoup # 递归方式:按层级提取标签 def bs_get_elements_by_level(soup_node, target_level, current_level=0): if current_level == target_level: yield soup_node else: for child in soup_node.children: # 跳过文本节点,只处理标签元素 if hasattr(child, 'name'): yield from bs_get_elements_by_level(child, target_level, current_level + 1) # 示例:加载本地XML文件并提取第2层级元素 with open('output.txt', 'r') as f: soup = BeautifulSoup(f.read(), 'xml') for tag in bs_get_elements_by_level(soup, 2): print(f"标签名:{tag.name},内容:{tag.text.strip()}")
总结来说,两种库都支持按层级解析,只需要在遍历过程中记录当前节点的深度,匹配目标层级时即可提取对应内容。
内容的提问来源于stack exchange,提问作者Slowat_Kela
相关产品推荐
相关产品推荐

