使用 XSLT (2.0) 转换 XML 时如何保留实体引用?对于我尝试过的所有处理器,默认情况下都会解析实体。我可以用xsl:character-map
处理字符实体,但是文本实体呢?
例如,这个 XML:
<!DOCTYPE doc [
<!ENTITY so "stackoverflow">
<!ENTITY question "How can I preserve the entity reference when transforming with XSLT??">
]>
<doc>
<text>Hello &so;!</text>
<text>&question;</text>
</doc>
使用以下 XSLT 进行转换:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
产生以下输出:
<doc>
<text>Hello stackoverflow!</text>
<text>How can I preserve the entity reference when transforming with XSLT??</text>
</doc>
输出应该与输入类似(暂时减去 doctype 声明):
<doc>
<text>Hello &so;!</text>
<text>&question;</text>
</doc>
I'm hoping我不必通过将所有&符号替换为来预处理输入&
(like &question;
),然后通过替换所有内容来对输出进行后处理&
with &
.
也许这是特定于处理器的?我正在使用撒克逊9。
Thanks!
如果您知道将使用哪些实体以及它们是如何定义的,您可以执行以下操作(相当原始且容易出错,但总比没有好):
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:my="my:my">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:character-map name="mapEntities">
<xsl:output-character character="&" string="&"/>
</xsl:character-map>
<xsl:variable name="vEntities" select=
"'stackoverflow',
'How can I preserve the entity reference when transforming with XSLT\?\?'
"/>
<xsl:variable name="vReplacements" select=
"'&so;', '&question;'"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:text disable-output-escaping="yes"><![CDATA[<!DOCTYPE doc [ <!ENTITY so "stackoverflow">
<!ENTITY question
"How can I preserve the entity reference when transforming with XSLT??"> ]>
]]>
</xsl:text>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="text()">
<xsl:value-of select=
"my:multiReplace(.,
$vEntities,
$vReplacements,
count($vEntities)
)
" disable-output-escaping="yes"/>
</xsl:template>
<xsl:function name="my:multiReplace">
<xsl:param name="pText" as="xs:string"/>
<xsl:param name="pEnts" as="xs:string*"/>
<xsl:param name="pReps" as="xs:string*"/>
<xsl:param name="pCount" as="xs:integer"/>
<xsl:sequence select=
"if($pCount > 0)
then
my:multiReplace(replace($pText,
$pEnts[1],
$pReps[1]
),
subsequence($pEnts,2),
subsequence($pReps,2),
$pCount -1
)
else
$pText
"/>
</xsl:function>
</xsl:stylesheet>
当应用于提供的 XML 文档时:
<!DOCTYPE doc [ <!ENTITY so "stackoverflow">
<!ENTITY question
"How can I preserve the entity reference when transforming with XSLT??"> ]>
<doc>
<text>Hello &so;!</text>
<text>&question;</text>
</doc>
产生了想要的结果:
<!DOCTYPE doc [ <!ENTITY so "stackoverflow">
<!ENTITY question
"How can I preserve the entity reference when transforming with XSLT??"> ]>
<doc>
<text>Hello &so;!</text>
<text>&question;</text>
</doc>
Do note:
替换中的特殊 (RegEx) 字符必须进行转义。
我们需要解析为 DOE,但不建议这么做,因为它违反了 XSLT 架构和处理模型的原则——换句话说,这个解决方案是一个令人讨厌的 hack。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)