如何在XSL与Saxon-HE中正确禁用输出转义?
问题描述
我正在使用Saxon-HE处理以下XSLT代码:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> <xsl:key name="elelsById" match="elel" use="@elelEntity" /> <xsl:template match="/"> <xsl:text disable-output-escaping="yes">
<!DOCTYPE dmodule [
</xsl:text> <xsl:text disable-output-escaping="yes"><!NOTATION cgm PUBLIC "-//USA-DOD//NOTATION Computer Graphics Metafile//EN">
</xsl:text> <xsl:for-each select="//elel[generate-id() = generate-id(key('elelsById', @elelEntity)[1])]"> <xsl:text disable-output-escaping="yes"><!ENTITY </xsl:text> <xsl:value-of select="@elelEntity" /> <xsl:text> SYSTEM "</xsl:text> <xsl:value-of select="@elelEntity" /> <xsl:text disable-output-escaping="yes">.cgm" NDATA cgm >
</xsl:text> </xsl:for-each> <xsl:text disable-output-escaping="yes">]>
</xsl:text> <xsl:apply-templates/> </xsl:template> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
当前输出结果:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE dmodule [ <!NOTATION cgm PUBLIC "-//USA-DOD//NOTATION Computer Graphics Metafile//EN"> <!ENTITY ELEL-A-01 SYSTEM "ELEL-A-01.cgm" NDATA cgm > <!ENTITY ELEL-A-05 SYSTEM "ELEL-A-05.cgm" NDATA cgm > ]> <!-- xml content -->
我预期输出中的<和>会被替换为<和>,但实际未生效。即使移除disable-output-escaping="yes",结果依然相同。我了解到saxon:doctype扩展仅适用于Saxon-PE或Saxon-EE版本,请问我的实现中遗漏了什么?
解决方案
核心问题原因
Saxon-HE对disable-output-escaping(以下简称DOE)的支持有限,且DOE的生效依赖输出方式:
- DOE仅在序列化到字符流时生效:如果输出目标是DOM树或其他非字符流格式,DOE会被直接忽略。
- XSLT 2.0规范中DOE是可选特性:Saxon-HE作为免费版本,对该特性的支持并不完整,尤其是处理DOCTYPE这类不属于XML实例内容的部分时。
可行替代方案
方案1:切换为纯文本输出模式
放弃XSLT的XML序列化机制,将整个输出作为纯文本处理,直接写入目标字符流:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> <xsl:key name="elelsById" match="elel" use="@elelEntity" /> <xsl:template match="/"> <!-- 输出XML声明 --> <xsl:text><?xml version="1.0" encoding="UTF-8"?>
</xsl:text> <!-- 输出DOCTYPE头部 --> <xsl:text><!DOCTYPE dmodule [
</xsl:text> <xsl:text><!NOTATION cgm PUBLIC "-//USA-DOD//NOTATION Computer Graphics Metafile//EN">
</xsl:text> <!-- 遍历生成实体声明 --> <xsl:for-each select="//elel[generate-id() = generate-id(key('elelsById', @elelEntity)[1])]"> <xsl:text><!ENTITY </xsl:text> <xsl:value-of select="@elelEntity" /> <xsl:text> SYSTEM "</xsl:text> <xsl:value-of select="@elelEntity" /> <xsl:text>.cgm" NDATA cgm >
</xsl:text> </xsl:for-each> <!-- 闭合DOCTYPE --> <xsl:text>]>
</xsl:text> <!-- 将XML内容转为文本输出 --> <xsl:value-of select="." disable-output-escaping="yes"/> </xsl:template> </xsl:stylesheet>
注意:需确保输入XML格式良好,避免输出时出现格式错误。
方案2:指定序列化参数
调用Saxon-HE时,通过命令行参数强制使用文本序列化模式,确保DOE生效。示例命令:
java -jar saxon-he-xxx.jar -s:input.xml -xsl:stylesheet.xsl -o:output.xml -method:text
此方式需手动处理XML内容的转义逻辑,保证输出格式合规。
方案3:后处理替换符号
用脚本(如Python、Perl)对输出文件进行后处理,直接替换<和>为实际尖括号,这是最快捷的临时解决办法。
关键注意事项
- Saxon-HE确实不支持
saxon:doctype扩展,无需尝试依赖该特性。 - DOE属于非常规用法,仅在必要场景下使用,优先考虑标准序列化机制。
- 若长期处理此类需求,升级到Saxon-PE/EE会更高效,官方扩展对DOCTYPE的支持更完善。
内容的提问来源于stack exchange,提问作者Noah
相关产品推荐
相关产品推荐

