在 xsl 转换后在 xml 输出中获取转义的 " ("e;) 和 ' (') 字符

问题描述 投票:0回答:1

我需要使用 XSLT 1.0 将 xml 文件中的

"
'
转义为
"
'
,因为使用系统无法处理 xml 元素内的这些字符。

我遇到了两个尚未解决的问题。

  1. 完全能够匹配
    '
  2. 让我的
    "
    保持逃脱(同时不破坏整个字符串)。

我现在相信这是不可能做到的。如果我错了,请告诉我。

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&apos;s fix these &quot;errors&quot;.</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="'&#39;'" />
                <xsl:with-param name="by" select="'&apos;'" />
            </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="'&quot;'" />
                <xsl:with-param name="by" select="'&amp;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 不会使用

'&#39;
&apos;
进行验证)

Q1。无论我使用

&apos;
&#39;
&#x0027;
,我的验证器都会抱怨并且不允许匹配。有什么办法解决这个问题吗?这是预期的吗?

Q2。如果我跳过 apos 并只关注

"
:如果我使用
by
作为
&quot;
,我会在输出中得到
"
。 如果我使用
by
作为
&amp;quot;
,我会在输出中得到
&amp;quot;
,而不仅仅是
&quot;

在我的验证器中,我可以看到变量

replaceQuot
是正确的,即
Let's fix these &quot;errors&quot;
但 xml 输出不“正确”。

如果我使用

<att name="name"><xsl:value-of select="$replaceQuot" disable-output-escaping="yes"/></att>
,那么一切都是这样。 (我得到了预期的、想要的文本),但是使这个解决方案不可能的是我也可以在这个字段中拥有
<
&
>
,我需要转义它们(我需要有效的 xml)。

有什么办法可以缓解吗?据我了解,我想可以解决这个问题的字符映射只能从 2.0 开始使用。

我的看法是,这是不可能用 xslt 1.0 来管理的,我需要推动消费系统修复其导入功能,或者通过另一个工具在 xml 后步骤中解决它。难道我错了?

xml xslt escaping xslt-1.0
1个回答
0
投票

修复目标系统当然是更好的解决方案。

不过,假设您的处理器支持

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">&amp;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">&amp;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>
© www.soinside.com 2019 - 2024. All rights reserved.