我需要使用 XSLT 1.0 将 xml 文件中的
"
和 '
转义为 "
'
,因为使用系统无法处理 xml 元素内的这些字符。
我遇到了两个尚未解决的问题。
'
。"
保持逃脱(同时不破坏整个字符串)。我现在相信这是不可能做到的。如果我错了,请告诉我。
XML 文件:
<?xml version="1.0" encoding="UTF-8"?>
<foo>
<bar>
<att name="name">Let's fix these "errors".</att>
</bar>
</foo>
想要的输出是这样的:
<?xml version="1.0" encoding="UTF-8"?>
<foo>
<bar>
<att name="name">Let's fix these "errors".</att>
</bar>
</foo>
XSL:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="att[@name ='name']">
<xsl:param name="content" select="text()" />
<xsl:variable name="replaceApos">
<xsl:call-template name="string-replace-all">
<xsl:with-param name="text" select="$content" />
<xsl:with-param name="replace" select="'''" />
<xsl:with-param name="by" select="'''" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="replaceQuot">
<xsl:call-template name="string-replace-all">
<xsl:with-param name="text" select="$replaceApos" />
<xsl:with-param name="replace" select="'"'" />
<xsl:with-param name="by" select="'&quot;'" />
</xsl:call-template>
</xsl:variable>
<att name="name"><xsl:value-of select="$replaceQuot"/></att>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template name="string-replace-all">
<xsl:param name="text" />
<xsl:param name="replace" />
<xsl:param name="by" />
<xsl:choose>
<xsl:when test="$text = '' or $replace = ''or not($replace)" >
<!-- Prevent this routine from hanging -->
<xsl:value-of select="$text" />
</xsl:when>
<xsl:when test="contains($text, $replace)">
<xsl:value-of select="substring-before($text,$replace)" />
<xsl:value-of select="$by" />
<xsl:call-template name="string-replace-all">
<xsl:with-param name="text" select="substring-after($text,$replace)" />
<xsl:with-param name="replace" select="$replace" />
<xsl:with-param name="by" select="$by" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
(注意:上述 XSL 不会使用
''
或 '
进行验证)
Q1。无论我使用
'
'
或 '
,我的验证器都会抱怨并且不允许匹配。有什么办法解决这个问题吗?这是预期的吗?
Q2。如果我跳过 apos 并只关注
"
:如果我使用 by
作为 "
,我会在输出中得到 "
。
如果我使用 by
作为 &quot;
,我会在输出中得到 &quot;
,而不仅仅是 "
在我的验证器中,我可以看到变量
replaceQuot
是正确的,即 Let's fix these "errors"
但 xml 输出不“正确”。
如果我使用
<att name="name"><xsl:value-of select="$replaceQuot" disable-output-escaping="yes"/></att>
,那么一切都是这样。 (我得到了预期的、想要的文本),但是使这个解决方案不可能的是我也可以在这个字段中拥有 <
&
和 >
,我需要转义它们(我需要有效的 xml)。
有什么办法可以缓解吗?据我了解,我想可以解决这个问题的字符映射只能从 2.0 开始使用。
我的看法是,这是不可能用 xslt 1.0 来管理的,我需要推动消费系统修复其导入功能,或者通过另一个工具在 xml 后步骤中解决它。难道我错了?
修复目标系统当然是更好的解决方案。
不过,假设您的处理器支持
disable-output-escaping
,您应该能够执行以下操作:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="att[@name='name']/text()">
<xsl:variable name="escape-apos">
<xsl:call-template name="replace">
<xsl:with-param name="text" select="."/>
<xsl:with-param name="searchString">'</xsl:with-param>
<xsl:with-param name="replaceString">&apos;</xsl:with-param>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="escape-quotes">
<xsl:call-template name="replace">
<xsl:with-param name="text" select="$escape-apos"/>
<xsl:with-param name="searchString">"</xsl:with-param>
<xsl:with-param name="replaceString">&quot;</xsl:with-param>
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="$escape-quotes" disable-output-escaping="yes"/>
</xsl:template>
<xsl:template name="replace">
<xsl:param name="text"/>
<xsl:param name="searchString"/>
<xsl:param name="replaceString"/>
<xsl:choose>
<xsl:when test="contains($text,$searchString)">
<xsl:value-of select="substring-before($text,$searchString)"/>
<xsl:value-of select="$replaceString"/>
<xsl:call-template name="replace">
<xsl:with-param name="text" select="substring-after($text,$searchString)"/>
<xsl:with-param name="searchString" select="$searchString"/>
<xsl:with-param name="replaceString" select="$replaceString"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>