You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python3 SAX解析如何获取XML内部实体名称而非解析值?

解决Python xml.sax解析JMdict时获取内部实体名称的问题

问题根源

Python的xml.sax默认会自动解析内部实体(比如&vr;这类在DTD中声明的实体),直接返回实体对应的文本值;而EntityResolver和DTDHandler接口仅处理外部实体,所以内部实体的解析事件不会触发,导致你无法直接拿到实体名称。

可行解决方案

方案1:自定义解析器,禁用内部实体替换并捕获跳过的实体

通过配置解析器禁用实体解析,再利用ContentHandler的skipped_entity()方法捕获实体名称:

  1. 创建解析器实例后,关闭命名空间、验证功能,禁用外部DTD加载和外部实体解析;
  2. 重写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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 18:45:36