逃脱“ (&quote;)和 XSL 转换后 XML 输出中的 ' (') 字符

Get escaped " (&quote;) and ' (') chars in xml output after xsl transformation

提问人:rast 提问时间:8/24/2023 更新时间:8/24/2023 访问量:46

问:

我需要转义并在 xml 文件中使用 XSLT 1.0,因为使用系统无法处理 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;)

问题1.无论我是否使用或我的验证者抱怨并且不允许匹配。有什么办法可以解决这个问题吗?这是意料之中的吗?&apos;&#39;&#x0027;

问题2.如果我跳过 apos 而只关注 : 如果我在输出中使用。 如果我在输出中使用,而不仅仅是"by&quot;"by&amp;quot;&amp;quot;&quot;

在我的验证器中,我可以看到变量是正确的,即 但 XML 输出不“正确”。replaceQuotLet's fix these &quot;errors&quot;

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

有什么方法可以缓解吗?据我所知,我想可以解决这个问题的字符映射仅适用于 2.0。

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

XML XSLT 转义 XSLT-1.0

评论


答:

0赞 michael.hor257k 8/24/2023 #1

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

不过,假设您的处理器支持 ,您应该能够执行以下操作: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>

但是,如果文本包含不应取消转义的字符(例如,实际的 & 符号),这可能会适得其反。


添加:

下面是一种方法的草图,该方法适用于包含类似或需要保持转义的字符的文本:&amp;&lt;

<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:call-template name="process">
        <xsl:with-param name="text" select="."/>
    </xsl:call-template>
</xsl:template>
    
<xsl:template name="process">
    <xsl:param name="text"/>
    <xsl:variable name="apos">'</xsl:variable>
    <xsl:variable name="quot">"</xsl:variable>
    <xsl:choose>
        <xsl:when test="contains($text, $apos) or contains($text, $quot)">
            <xsl:variable name="bef-apos" select="substring-before($text, $apos)"/>
            <xsl:variable name="bef-quot" select="substring-before($text, $quot)"/>
            <xsl:choose>
                <xsl:when test="$bef-apos and (not($bef-quot) or string-length($bef-apos) &lt; string-length($bef-quot))">
                    <xsl:value-of select="$bef-apos"/>
                    <xsl:text disable-output-escaping="yes">&amp;apos;</xsl:text>
                    <xsl:call-template name="process">
                        <xsl:with-param name="text" select="substring-after($text, $apos)"/>
                    </xsl:call-template>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="$bef-quot"/>
                    <xsl:text disable-output-escaping="yes">&amp;quot;</xsl:text>
                    <xsl:call-template name="process">
                        <xsl:with-param name="text" select="substring-after($text, $quot)"/>
                    </xsl:call-template>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="$text"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

</xsl:stylesheet>

注意:没有经过非常彻底的测试。通过更多的工作可能会变得更加优雅。

评论

0赞 rast 8/24/2023
谢谢你的回答。不幸的是,我偶尔会在这个名称字段中得到 & 符号、< 和 >,所以我不能使用 disable-output-escaping=yes。
0赞 rast 8/24/2023
甚至没有想过尝试 <xsl:with-param name=“searchString”>'</xsl:with-param>而不是使用选择。完美地解决了我的 Q1。
0赞 michael.hor257k 8/24/2023
好吧,我相信有办法解决这个问题,但这是一项非常艰巨的工作。基本上,您需要让处理模板直接写入输出。这意味着您不能在两次通过中进行替换;您需要检查下一个字符是否为 OR,然后选择第一个字符。然后,您只能在输出替换字符串本身时使用。'"disable-output-escaping
0赞 michael.hor257k 8/24/2023
请参阅我的答案的补充。
0赞 rast 8/24/2023
听起来像是很多工作......我会看看我是否可以推动消耗系统修复。这将处理很多很多文件,所以也需要一些不需要太多计算的东西。也许应该检查我是否也有<,&和>在现场,如果没有,请执行禁用输出转义,否则我需要实现您的想法。