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

XSLT转换XML时如何保留–等自定义实体不被转义

问题根因

当前自定义实体被异常转义、输出结构不符合预期是两个独立问题叠加导致:

  1. 实体转义问题:你定义的ndash实体替换值为–,解析后会得到字面量字符串–。当解析器开启resolve_entities=True时,lxml会在加载阶段就把所有实体替换为对应文本值,后续XSLT处理的是已经解析完成的DOM树,此时文本节点中存储的是裸&字符,按照XML序列化规范,裸&必须转义为&,最终就输出了–的错误结果。
  2. 结构缺失问题:你写的XSLT中匹配begin节点的模板直接复制data子节点,没有保留外层<begin>标签,导致输出结构和预期不符。
可行解决方案

以下两个方案均适配大文件处理场景,不需要改动原始XML的实体定义:

方案1:关闭预解析实体保留原始写法(性能最优,推荐超大文件场景使用)

不在解析阶段展开实体,让解析器将自定义实体保留为内部实体节点,序列化时会自动输出原始实体写法,无需额外替换逻辑。
首先修改Python执行代码:

import lxml.etree as ET
from lxml import etree

# 核心修改:将resolve_entities设为False,不提前展开实体
parser = etree.XMLParser(load_dtd=True, resolve_entities=False, huge_tree=True)

dom = ET.parse('test.xml', parser)
xslt = ET.parse('test.xsl')
transform = ET.XSLT(xslt)
newdom = transform(dom)
processed_file = 'processed.xml'
# 不要用str()强转结果,用tostring方法指定参数保证转义、编码规则一致
with open(processed_file, 'wb') as file:
    file.write(etree.tostring(newdom, encoding='utf-8', indent=True))
print(etree.tostring(newdom, encoding='utf-8', pretty_print=True).decode('utf-8'))
print('Task Done')

再修正XSLT模板逻辑,保留外层<begin>标签:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
   <xsl:output encoding="utf-8" method="xml" indent="yes" />

   <xsl:template match="@*|node()">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
   </xsl:template>

   <xsl:template match="begin">
      <xsl:copy>
         <xsl:copy-of select="data" />
      </xsl:copy>
   </xsl:template>

</xsl:stylesheet>

该方案解析速度快、内存占用低,可支持GB级XML文件处理,所有自定义实体都会原样保留,不会被转义修改。

方案2:占位符替换(兼容需要读取实体解析值的场景)

如果XSLT逻辑中需要读取实体解析后的文本内容做处理,不能关闭实体解析,可以通过占位符绕开转义逻辑:

  1. 读取原始XML文本时,先将所有自定义实体(比如&ndash;)替换为不会和正常内容冲突的特殊占位串,例如__NDASH_ENTITY_PLACEHOLDER__
  2. 正常执行XML解析、XSLT转换、序列化流程
  3. 拿到最终序列化的文本结果后,将所有占位串替换回原始的&ndash;再写入文件
    处理超大文件时可以用流式逐行读写的方式做替换,避免全量加载占用过高内存。
注意事项
  • 不要使用str(newdom)的方式获取序列化结果,lxml的XSLT结果对象直接转字符串在不同版本下存在编码、转义规则不一致的问题,统一用etree.tostring()指定输出参数稳定性更高。
  • 如果XML中存在多种自定义实体,方案1无需额外适配,关闭resolve_entities即可全部保留原始写法;方案2需要为每个自定义实体配置互不冲突的占位串。

内容的提问来源于stack exchange,提问作者Sai Prasad Mukthapuram

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 08:06:22