在XSLT中最后一次出现字符后获取子字符串

时间:2012-01-31 11:31:54

标签: c# xml xslt

我在XML文件中有一个类似于这个字符串的字符串:

  

M:Namespace.Class.Method(Something a,Something b)

句点(。)字符的数量是有用的,这意味着它可以只有2,如本例所示,但可以更多。

我想使用XSLT从最后一个'。'获取该字符串的子字符串。性格,所以我只剩下:

  

方法(某事a,某事b)

我无法使用标准的substring / substring-after函数实现此目的。

有一种简单的方法吗?

3 个答案:

答案 0 :(得分:22)

在XSLT 1.0中,您需要使用递归模板,如下所示:

  <xsl:template name="substring-after-last">
    <xsl:param name="string" />
    <xsl:param name="delimiter" />
    <xsl:choose>
      <xsl:when test="contains($string, $delimiter)">
        <xsl:call-template name="substring-after-last">
          <xsl:with-param name="string"
            select="substring-after($string, $delimiter)" />
          <xsl:with-param name="delimiter" select="$delimiter" />
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise><xsl:value-of 
                  select="$string" /></xsl:otherwise>
    </xsl:choose>
  </xsl:template>

并像这样调用它:

<xsl:call-template name="substring-after-last">
  <xsl:with-param name="string" select="'M:Namespace.Class.Method(Something a, Something b)'" />
  <xsl:with-param name="delimiter" select="'.'" />
</xsl:call-template>

在XSLT 2.0中,您可以使用tokenize()函数,只需选择序列中的最后一项:

tokenize('M:Namespace.Class.Method(Something a, Something b)','\.')[last()]

答案 1 :(得分:1)

对于接受的答案,这是一个更有效的解决方案O(N)与O(N ^ 2)

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

 <xsl:template match="text()" name="skipAfterDots">
  <xsl:param name="pTotalString" select="."/>
  <xsl:param name="pTotalLength" select="string-length(.)"/>
  <xsl:param name="pPosition" select="1"/>
  <xsl:param name="pLastFound" select="-1"/>

  <xsl:choose>
    <xsl:when test="$pPosition > $pTotalLength">
      <xsl:value-of select="substring($pTotalString, $pLastFound + 1)"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:variable name="vIsDot" select=
       "substring($pTotalString, $pPosition, 1) = '.'"/>

      <xsl:call-template name="skipAfterDots">
        <xsl:with-param name="pTotalString" select="$pTotalString"/>
        <xsl:with-param name="pTotalLength" select="$pTotalLength"/>
        <xsl:with-param name="pLastFound" select=
        "$pLastFound * not($vIsDot) + $pPosition * $vIsDot"/>
        <xsl:with-param name="pPosition" select="$pPosition+1"/>
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
 </xsl:template>
</xsl:stylesheet>

将此转换应用于以下XML文档

<t>M:Namespace.Class.Method(Something a, Something b)</t>

产生了想要的正确结果

Method(Something a, Something b)

解释

此解决方案不包含对substring-after()功能的任何调用。相反,在每一步中,只比较字符串的一个字符与点字符的相等性。因为最多有N个字符,所以这是O(N) - 线性复杂度。

相反,接受的答案会在每一步调用substring-after()函数。在最坏的情况下,可能有N个点,因此这将是O(N ^ N) - 二次复杂度。

注意:我们合理地假设在两个解决方案中定位字符串的第k个字符都是O(1)。

答案 2 :(得分:-1)

如果您确实知道字符串中有完全两个点,那么您可以尝试:

<xsl:value-of select="substring-after(substring-after($str, '.'), '.')" />