You need to enable JavaScript to run this app. 使用lxml/ElementTree时如何禁用XML实体转换保留原始输入符号
优惠活动
大模型
产品
解决方案
定价
更多

使用lxml/ElementTree时如何禁用XML实体转换保留原始输入符号

问题场景

使用XML解析库处理包含非ASCII变音字符的文本时,序列化输出阶段会自动将非ASCII字符转换为数字字符实体,而非保留原始Unicode字符形式。
复现代码:

import xml.etree.ElementTree as ET

root = ET.fromstring("<r><s>Die Häuser haben Dächer.</s></r>")
as_text = ET.tostring(root).decode("utf-8")
print(as_text)

实际输出:
<r><s>Die H&#228;user haben D&#228;cher.</s></r>
期望输出:
<r><s>Die Häuser haben Dächer.</s></r>
目标是全场景禁用这类无意义的实体转换,直接保留原始输入的Unicode符号,同时确保实体还原过程足够安全,不破坏XML结构、不存在解析风险。

解决方案

序列化阶段从根源禁用实体转换

非ASCII字符被自动转成实体的根本原因是,xml.etree.ElementTree(包括lxml)默认的序列化输出编码为ASCII,为了适配ASCII编码的字符范围,解析库会自动将所有非ASCII字符转换为数字实体。
仅需调整序列化时的编码参数,即可从根源关闭这类转义,不需要额外打补丁:

  • 若需要直接输出字符串形式的XML,调用tostring时传入encoding="unicode"参数,解析库会直接以Unicode形式输出所有字符,不会触发非ASCII字符的实体转义:
    as_text = ET.tostring(root, encoding="unicode")
    print(as_text)
    
    输出结果完全匹配期望,直接保留原始变音字符。
  • 若需要输出二进制形式的XML流,调用tostring时传入encoding="utf-8"并关闭XML声明,输出的二进制流经过UTF-8解码后同样不会生成实体:
    as_bytes = ET.tostring(root, encoding="utf-8", xml_declaration=False)
    as_text = as_bytes.decode("utf-8")
    
  • lxml的处理逻辑与原生ET完全一致,只要传入相同的编码参数,就可以自动关闭非ASCII字符的实体转换,无额外配置要求。

已生成实体的安全还原方法

如果处理流程中已经生成了带数字实体的XML字符串,不推荐直接使用全局html.unescape方法做还原。这类全局方法会将XML语法必需的保留实体(比如&lt;、&gt;、&amp;)也一并还原成对应符号,最终破坏XML标签结构,甚至引发解析注入风险。
安全的还原流程:

  1. 将带实体的字符串作为合法XML片段,重新喂给XML解析器处理。XML解析器会自动识别并把数字实体转成对应的Unicode字符,全程严格保留XML语法层面的保留实体,不会被错误转换。
  2. 解析完成后按照上文的UTF-8/Unicode模式重新序列化,即可得到结构完整、字符正确的输出结果,完全避免手动还原实体带来的结构破坏风险。

注意:禁止对完整XML文档直接执行无差别实体反转义,这类操作会直接将转义过的文本内容还原成真实的XML标签,彻底破坏文档结构。

内容的提问来源于stack exchange,提问作者user3033490

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.05 03:27:05