Python3 SAX解析如何获取XML内部实体名称而非解析值?
解决Python xml.sax解析JMdict时获取内部实体名称的问题
问题根源
Python的xml.sax默认会自动解析内部实体(比如&vr;这类在DTD中声明的实体),直接返回实体对应的文本值;而EntityResolver和DTDHandler接口仅处理外部实体,所以内部实体的解析事件不会触发,导致你无法直接拿到实体名称。
可行解决方案
方案1:自定义解析器,禁用内部实体替换并捕获跳过的实体
通过配置解析器禁用实体解析,再利用ContentHandler的skipped_entity()方法捕获实体名称:
- 创建解析器实例后,关闭命名空间、验证功能,禁用外部DTD加载和外部实体解析;
- 重写
skipped_entity()方法,该方法会在解析器遇到未解析的实体时被调用,参数就是实体名称。
示例代码:
import xml.sax class JMdictHandler(xml.sax.ContentHandler): def __init__(self): self.current_tag = "" self.current_entity = None def startElement(self, name, attrs): self.current_tag = name self.current_entity = None def skipped_entity(self, name): # 仅在<pos>标签内捕获实体名称 if self.current_tag == "pos": self.current_entity = name def endElement(self, name): if name == "pos" and self.current_entity: # 这里拿到的就是实体名称,比如"vr" print(f"动词类型实体: {self.current_entity}") self.current_tag = "" # 配置解析器 parser = xml.sax.make_parser() # 禁用命名空间与验证 parser.setFeature(xml.sax.handler.feature_namespaces, False) parser.setFeature(xml.sax.handler.feature_validation, False) # 禁止加载外部DTD,避免内部实体被自动解析 parser.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", False) # 禁用外部实体解析 parser.setFeature("http://xml.org/sax/features/external-general-entities", False) parser.setFeature("http://xml.org/sax/features/external-parameter-entities", False) # 设置处理器并解析文件 handler = JMdictHandler() parser.setContentHandler(handler) parser.parse("JMdict.xml")
方案2:预处理XML文件,替换实体引用
如果不想修改解析器逻辑,可以先对XML文件做预处理,将实体引用替换为可识别的标记,之后解析时直接提取实体名称:
import re # 读取原XML文件 with open("JMdict.xml", "r", encoding="utf-8") as f: xml_content = f.read() # 替换所有内部实体引用为特殊标记 # 正则匹配&xxx;格式的实体,替换为__ENTITY__xxx__ processed_content = re.sub(r"&([a-zA-Z0-9_]+);", r"__ENTITY__\1__", xml_content) # 将处理后的内容写入临时文件或直接解析 with open("processed_JMdict.xml", "w", encoding="utf-8") as f: f.write(processed_content) # 后续用xml.sax解析processed_JMdict.xml,从characters()中提取实体名称
注意事项
- 方案1更可靠,不会破坏XML结构;方案2需要注意正则表达式的匹配范围,避免误替换CDATA块或其他特殊内容中的类似格式文本。
- 若JMdict的DTD是内部嵌入在XML中的,必须确保解析器不加载它,否则内部实体还是会被自动解析。
内容的提问来源于stack exchange,提问作者Simone Bondi
相关产品推荐
相关产品推荐

