在XSLT 1.0中转义字符串中的双引号和反斜杠

6

我有一个字符串如下,想将其转换为JSON格式:

测试“out”和\ new

预期输出是 测试\"out\"和\ new

我尝试通过调用转义引号的模板来实现 - 对于转义引号可以正常工作:

<xsl:template name="escapeQuote">
    <xsl:param name="pText" select="concat(normalize-space(.), '')" />
    <xsl:if test="string-length($pText) >0">
        <xsl:value-of select="substring-before(concat($pText, '&quot;'), '&quot;')" />

        <xsl:if test="contains($pText, '&quot;')">
            <xsl:text>\"</xsl:text>    
            <xsl:call-template name="escapeQuote">
                <xsl:with-param name="pText" select="substring-after($pText, '&quot;')" />
            </xsl:call-template>
        </xsl:if>
    </xsl:if>
</xsl:template>

用于转义反斜杠的模板 - 只适用于反斜杠:

<xsl:template name="jsonescape">
 <xsl:param name="str" select="."/>
  <xsl:choose>
    <xsl:when test="contains($str, '\')">
      <xsl:value-of select="concat(substring-before($str, '\'), '\\' )"/>
      <xsl:call-template name="jsonescape">
        <xsl:with-param name="str" select="substring-after($str, '\')"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
        <xsl:value-of select="$str"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

我的问题是如何调用两个模板或者合并它们,请帮助我。

将第一个模板的结果作为输入参数调用第二个模板。 - michael.hor257k
请问您能否建议我语法? - Srikanth Reddy
由于我对XSL不熟悉,请帮助我如何将模板的结果传递给另一个模板。 - Srikanth Reddy
由于两者都是递归模板,因此会产生奇怪的输出。如果有人有解决方案,请帮忙。 - Srikanth Reddy
1个回答

9

以下是一个示例,展示了如何结合使用两个模板调用,以便将jsonescape的输出用作escapequote的输入参数。

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
  <xsl:output method="text" />

  <xsl:template match="input">
    <xsl:call-template name="escapeQuote">
      <xsl:with-param name="pText">
        <xsl:call-template name="jsonescape">
          <xsl:with-param name="str" select="." />
        </xsl:call-template>          
      </xsl:with-param>
    </xsl:call-template>
  </xsl:template>

  <xsl:template name="escapeQuote">
      <xsl:param name="pText" select="concat(normalize-space(.), '')" />
      <xsl:if test="string-length($pText) >0">
          <xsl:value-of select="substring-before(concat($pText, '&quot;'), '&quot;')" />

          <xsl:if test="contains($pText, '&quot;')">
              <xsl:text>\"</xsl:text>    
              <xsl:call-template name="escapeQuote">
                  <xsl:with-param name="pText" select="substring-after($pText, '&quot;')" />
              </xsl:call-template>
          </xsl:if>
      </xsl:if>
  </xsl:template>

  <xsl:template name="jsonescape">
   <xsl:param name="str" select="."/>
    <xsl:choose>
      <xsl:when test="contains($str, '\')">
        <xsl:value-of select="concat(substring-before($str, '\'), '\\' )"/>
        <xsl:call-template name="jsonescape">
          <xsl:with-param name="str" select="substring-after($str, '\')"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
          <xsl:value-of select="$str"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

因此,给出这个输入:

<input>Test "out" and \new</input>

以下是输出结果。
Test \"out\" and \\new

请注意,顺序很重要。如果您颠倒了模板调用的顺序,"将会被escapequote模板转换为\ ",然后再被jsonescape模板转换为\\ "
另外,由于两个模板都有类似的作用,即在特定字符前放置 \\ ,因此您可以将两个模板合并为一个。
请尝试此XSLT。
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
  <xsl:output method="text" />

  <xsl:template match="input">
    <xsl:call-template name="jsonescape">
      <xsl:with-param name="str" select="." />
    </xsl:call-template>          
  </xsl:template>

  <xsl:template name="jsonescape">
   <xsl:param name="str" select="."/>
   <xsl:param name="escapeChars" select="'\&quot;'" />
   <xsl:variable name="first" select="substring(translate($str, translate($str, $escapeChars, ''), ''), 1, 1)" />
   <xsl:choose>
      <xsl:when test="$first">
        <xsl:value-of select="concat(substring-before($str, $first), '\', $first)"/>
        <xsl:call-template name="jsonescape">
          <xsl:with-param name="str" select="substring-after($str, $first)"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
          <xsl:value-of select="$str"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

非常感谢,我很感激。只是一个问题,如果数据中包含第一个双引号或反斜杠,那么这段代码是否有效。 - Srikanth Reddy
是的,我相信它会在任何情况下都起作用。你应该尝试一下,看看 :) - Tim C
第一次 XSLT 编码在所有情况下都完美运行。谢谢 Tim C。 - Srikanth Reddy
1
太棒了!这两个解决方案都非常好用。谢谢! - Hrvoje Golcic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接