[XSL-LIST Mailing List Archive Home] [By Thread] [By Date]

RE: [xsl] last index of...


Subject: RE: [xsl] last index of...
From: "McNally, David" <David.McNally@xxxxxxxxxx>
Date: Mon, 12 Nov 2001 15:01:47 -0500

> > Is there a function in XSLT which obtains the position of the last
> > occurrence of a string within another string?
> 
[snip]
> Getting the last index would be slightly more complicated, and it
> looks like you want to use it to get hold of the string after the last
> occurrence of something, so hopefully this is sufficient.

Here's my attempt at getting the index of the last occurrence - basically
defining a reverse template that just reverses strings, then using
string-length and substring-before on the reversed strings in a template
called rindex.

Using this input file, searching for "nme" in each case:

<foo>
<test>aaa bbb nme ccc ddd nme aaa 21</test>
<test>aaa bbb nme ccc nme aaa 17</test>
<test>aaa ccc ddd nme aaa 13</test>
<test>aaanmenmenme bbb nme ccc ddd nmenmenme aaa 36</test>
<test>;l sdkjsdf lsdfkj 0</test>
</foo>

This stylesheet:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:html="http://www.w3.org/1999/xhtml"  >

<xsl:output method="text"/>

<xsl:template name="reverse">
	<xsl:param name="string"/>
	<xsl:value-of select="substring($string, string-length($string))"/>
	<xsl:if test="string-length($string) > 1">
		<xsl:call-template name="reverse">
			<xsl:with-param name="string"
select="substring($string, 1, (string-length($string)-1))"/>
		</xsl:call-template>
	</xsl:if>
</xsl:template>

<xsl:template name="rindex">
	<xsl:param name="string"/>
	<xsl:param name="substring"/>
	<xsl:choose>
		<xsl:when test="contains($string,$substring)">
			<xsl:variable name="rstring">
				<xsl:call-template name="reverse">
					<xsl:with-param name="string"
select="$string"/>
				</xsl:call-template>
			</xsl:variable>
			<xsl:variable name="rsubstring">
				<xsl:call-template name="reverse">
					<xsl:with-param name="string"
select="$substring"/>
				</xsl:call-template>
			</xsl:variable>
			<xsl:value-of select="string-length($string) -
(string-length(substring-before($rstring,$rsubstring)) +
string-length($rsubstring)) + 1"/>
		</xsl:when>
		<xsl:otherwise>
			<xsl:value-of select="0"/>
		</xsl:otherwise>
	</xsl:choose>
</xsl:template>

<xsl:template match="test">
	<xsl:text>
Position: </xsl:text>
	<xsl:call-template name="rindex">
		<xsl:with-param name="string" select="."/>
		<xsl:with-param name="substring" select="'nme'"/>
	</xsl:call-template>
</xsl:template>

</xsl:stylesheet>

gives output:

Position: 21
Position: 17
Position: 13
Position: 36
Position: 0

which seems right.

I just checked the archives to see if reverse templates had been discussed
before, and indeed they have:
http://www.biglist.com/lists/xsl-list/archives/200108/msg00248.html

I guess the reverse template I wrote is tail-recursive, and so slow?

David.
--
David McNally            Moody's Investors Service
Software Engineer        99 Church St, NY NY 10007 
David.McNally@xxxxxxxxxx            (212) 553-7475 


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list



Current Thread
Keywords