Getting a substring AFTER the last occurrence of a character in XSLT

I have a line in an XML file that looks something like this:

M: namespace .Class.Method (something a, something b)

The number of periods (.) Of characters is abstract, and it can only be 2, as in this example, but it can be more.

I would like to use XSLT to get a substring of this string from the last '.' character, so I will only stay with:

Method (something a, something b)

I could not achieve this using the standard substring / substring-after functions.

Is there an easy way to do this?

+7
source share
3 answers

In XSLT 1.0, you will need a recursive template , for example:

<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> 

and call it like this:

 <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> 

In XSLT 2.0, you can use the tokenize () function and simply select the last element in the sequence:

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

Here is a more efficient solution O (N) vs O (N ^ 2) for the accepted answer :

 <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> 

When this conversion is applied to the following XML document :

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

required, the correct result is obtained :

 Method(Something a, Something b) 

Explanation

This solution does not contain a call to the substring-after() function . Instead, at each step, only one line character is compared for equality with a period character. Since no more than N characters, this is O (N) - linear complexity.

In contrast, the accepted answer calls the substring-after() function at each step . In the worst case, there may be N points, and thus it will be O (N ^ N) - quadratic complexity.

Note We make a reasonable assumption that in both solutions the search for the kth character of the string is O (1).

+1
source

If you know that you have exactly two points in your lines, you can try:

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

All Articles