XSLT 1.0:双引号转义

3

我有一个遵循以下方案的XML文件:

<translationData>
<product>
<attributeValue>
<value>1/4"</value>
<value1>1/4"</value1>
<currentValue>aaaa;bbbb</currentValue>
</attributeValue>
</product>
</translationData>

由于“currentValue”中有分号,我需要转义“value”中的分号和双引号。我可以通过将所有文本放在引号中来转义分号,如下所示:

XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text" encoding="utf-8" />

  <xsl:param name="delim" select="';'" />
  <xsl:param name="quote" select="'&quot;'" />
  <xsl:param name="break" select="'&#xA;'" />

  <xsl:template match="/">
    <xsl:apply-templates select="translationData/product/attributeValue" />
  </xsl:template>

  <xsl:template match="attributeValue">
    <xsl:apply-templates />
    <xsl:if test="following::*">
      <xsl:value-of select="$break" />
    </xsl:if>
  </xsl:template>


  <xsl:template match="*">
    <!-- remove normalize-space() if you want keep white-space at it is -->

    <xsl:value-of select="concat($quote, translate(.,'&quot;','\&quot;'), $quote)" />
    <xsl:if test="following-sibling::*">
      <xsl:value-of select="$delim" />
    </xsl:if>
  </xsl:template>

  <xsl:template match="text()" />
</xsl:stylesheet>

但是输出结果却是:
"1/4\";"1/4\";"aaaa;bbbb"
而不是:
"1/4\"";"1/4\"";"aaaa;bbbb"
我做错了什么?
我对XML和XSLT都很陌生,没有发现有任何问题可以处理这个特定的情况。
XSLT代码来自@Tomalak为另一个问题提供的答案。请参见此处

R 是从哪里来的? - michael.hor257k
请不要在未注明出处的情况下发布他人的代码。你从https://dev59.com/vXRC5IYBdhLWcg3wP-dh#365372复制了这段XSLT代码。每当你使用非自己编写的代码时,请注明出处。 - Tomalak
@michael.hor257k 不应该出现在这里。我刚刚将其删除了。 - C D
@Tomalak:抱歉,我不知道。不会再发生了!我会立即编辑它。 - C D
1个回答

1
translate()函数只会用另一个单一字符替换每个单一字符。
要将单一字符"替换为两个字符的字符串\",您需要使用一个命名的递归模板,或者 - 如果您的处理器支持 - 使用扩展函数,如 EXSLT str:replace()
以下是使用递归模板的示例:
...

<xsl:template match="*">
    <xsl:text>"</xsl:text>
    <xsl:call-template name="replace">
        <xsl:with-param name="text" select="."/>
    </xsl:call-template>
    <xsl:text>"</xsl:text>
    <xsl:if test="position()!=last()">
        <xsl:text>;</xsl:text>
    </xsl:if>
</xsl:template>

...

<xsl:template name="replace">
    <xsl:param name="text"/>
    <xsl:param name="searchString">"</xsl:param>
    <xsl:param name="replaceString">\"</xsl:param>
    <xsl:choose>
        <xsl:when test="contains($text,$searchString)">
            <xsl:value-of select="substring-before($text,$searchString)"/>
            <xsl:value-of select="$replaceString"/>
           <!--  recursive call -->
            <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>

...

完美地解决了我的问题并且回答得非常到位!非常感谢! - C D
你的代码运行得很好。但是现在我发现我的问题不正确。输出结果为:"1/4"";"1/4"";"";如果“currentValue”为空,那么没有问题。但是一旦我在Excel中打开CSV文件,它会将输出结果显示在一个单元格中,如下所示:1/4";1/4""它应该将其放在不同的单元格中。我认为这个问题可以通过将“替换为\”来解决。但是Excel似乎无法理解这一点。 - C D
尝试将 replaceString 参数更改为 <xsl:param name="replaceString">""</xsl:param> - 请参见:https://en.wikipedia.org/wiki/Comma-separated_values#Standardization - michael.hor257k
您,先生,是我的英雄!非常感谢您! - C D

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