You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

XSLT 1.0转义XML元素内双引号、单引号的问题求助

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&apos;s fix these &quot;errors&quot;.</att>
   </bar>
</foo>

尝试的XSLT代码(原代码)

<?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="'&amp;#39;'" />
                <xsl:with-param name="by" select="'&amp;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="'&amp;quot;'" />
                <xsl:with-param name="by" select="'&amp;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>

问题解答

Q1:无法匹配单引号的解决办法

你之前的代码无法匹配单引号,是因为replace参数传入的是&#39;字符串(而非单引号字符本身),自然无法匹配文本中的'。正确的做法是让replace参数的值为单引号字符本身:

  • 若属性值用单引号包裹,内部单引号需转义为&apos;,即 <xsl:with-param name="replace" select="'&apos;'"/>;
  • 若属性值用双引号包裹,可直接写 <xsl:with-param name="replace" select='"&#39;"'/>,两种写法都能得到单引号字符作为匹配目标。

Q2:双引号转义后格式异常的解决办法

XSLT默认会将输出中的&转义为&amp;,导致你写入的&amp;quot;最终输出为&amp;amp;quot;,而直接写&quot;会被还原为"。在XSLT 1.0中,可通过局部禁用输出转义解决,同时保证其他特殊字符正常转义:

核心调整点

  1. 传递替换值时,用带disable-output-escaping="yes"的<xsl:text>包裹实体引用;
  2. 修改string-replace-all模板,用<xsl:copy-of>输出替换值,保留禁用转义的设置。

完整可用的XSLT代码

<?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="'&apos;'" />
                <xsl:with-param name="by">
                    <xsl:text disable-output-escaping="yes">&amp;apos;</xsl:text>
                </xsl:with-param>
            </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">
                    <xsl:text disable-output-escaping="yes">&amp;quot;</xsl:text>
                </xsl:with-param>
            </xsl:call-template>
        </xsl:variable>

        <att name="name"><xsl:copy-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)" > 
                <xsl:value-of select="$text" />
            </xsl:when> 
            <xsl:when test="contains($text, $replace)">
                <xsl:value-of select="substring-before($text,$replace)" />
                <xsl:copy-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>

补充说明

  • 局部禁用输出转义仅针对替换的实体引用部分,不会影响文本中其他需要转义的字符(如<、>),保证XML有效性;
  • 若上述方案仍无法满足需求,才考虑推动接收系统修复(正常XML解析应该能处理元素内的单双引号),或用其他工具做后续字符串处理。

内容的提问来源于stack exchange,提问作者rast

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 09:29:54