I'm new to XSLT. I wonder if it is possible to select a substring of an item. I'm trying to parse an RSS feed. The description value has more text than what I want to show. I'd like to get a subtring of it based on the index of some substring. Basically, I want to show the result of a substring call passing indxOf('some_substring') and a length as parameters. Is this possible?
From comments:
I want to select the text of a string that is located after the occurrence of substring
The following is the complete example containing both XML and XSLT where substring-before and substring-after are used
<?xml version="1.0" encoding="UTF-8"?>
<persons name="Group_SOEM">
<person>
<first>Joe Smith</first>
<last>Joe Smith</last>
<address>123 Main St, Anycity</address>
</person>
</persons>
The following is XSLT which changes value of first/last name by separating the value by space so that after applying this XSL the first name element will have value "Joe" and last "Smith".
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="first">
<first>
<xsl:value-of select="substring-before(.,' ')" />
</first>
</xsl:template>
<xsl:template match="last">
<last>
<xsl:value-of select="substring-after(.,' ')" />
</last>
</xsl:template>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
I want to select the text of a string that is located after the occurrence of substring
You could use:
substring-after($string,$match)
If you want a subtring of the above with some length then use:
substring(substring-after($string,$match),1,$length)
But problems begin if there is no ocurrence of the matching substring... So, if you want a substring with specific length located after the occurrence of a substring, or from the whole string if there is no match, you could use:
substring(substring-after($string,substring-before($string,$match)),
string-length($match) * contains($string,$match) + 1,
$length)
There is a substring function in XSLT. Example here.
I wrote my own index-of function, inspired by strpos() in PHP.
<xsl:function name="fn:strpos">
<xsl:param name="haystack"/>
<xsl:param name="needle"/>
<xsl:value-of select="fn:_strpos($haystack, $needle, 1, string-length($haystack) - string-length($needle))"/>
</xsl:function>
<xsl:function name="fn:_strpos">
<xsl:param name="haystack"/>
<xsl:param name="needle"/>
<xsl:param name="pos"/>
<xsl:param name="count"/>
<xsl:choose>
<xsl:when test="$count < 0">
<!-- Not found. Most common is to return -1 here (or maybe 0 in XSL?). -->
<!-- But this way, the result can be used with substring() without checking. -->
<xsl:value-of select="string-length($haystack) + 1"/>
</xsl:when>
<xsl:when test="starts-with(substring($haystack, $pos), $needle)">
<xsl:value-of select="$pos"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="fn:_strpos($haystack, $needle, $pos + 1, $count - 1)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>
Here is some one liner xpath 1.0 expressions for IndexOf( $text, $searchString ):
If you need the position of the FIRST character of the sought string, or 0 if it is not present:
contains($text,$searchString)*(1 + string-length(substring-before($text,$searchString)))
If you need the position of the first character AFTER the found string, or 0 if it is not present:
contains($text,$searchString)*(1 + string-length(substring-before($text,$searchString)) + string-length($searchString))
Alternatively if you need the position of the first character AFTER the found string, or length+1 if it is not present:
1 + string-length($right) - string-length(substring-after($right,$searchString))
That should cover most cases that you need.
Note: The multiplication by contains( ... ) causes the true or false result of the contains( ... ) function to be converted to 1 or 0, which elegantly provides the "0 when not found" part of the logic.
Source: Stackoverflow.com