Getting a substring before the last occurrence of a character in XSLT 1.0

With XSLT 2.0 a method is provided, which splits a string by a specific delimiter (e.g. commas, spaces or other) quite easily.

<xsl:variable name="subString" 
        select="substring-before-last($arg, $delim)"/>

This function returns the part of $arg which appears before the last occurrence of $delim. If $arg does not contain $delim, a zero-length string is returned.

If you split the string “XPath-is-fun” as $arg with $delim “-” you will get the following result:

XPath-is

Unfortunately, this function is not provided in XSLT 1.0. But there is a possibility of realizing this without any 3rd party libraries (e.g. EXSLT). The following example shows, how this can be done with XSLT 1.0.

First we look at the XML snippet, which contains as example the cars element with a comma seperated String values. This String should be seperated via XSLT on the last occurence for delemiter ‘,’.

<?xml version="1.0" encoding="UTF-8"?>
<cars>Audi, Volkswagen, Skoda, Seat, Kia</cars>

The corresponding XSL stylesheet is straight forward. The first template matches for the cars element. Here is checked, if the element exists. If this is the case, the custom substring-before-last template is called with String value and delemiter as function parameter.

The special of the substring-before-last template is, that it is recursive. With each iteration the substring in front of the first delimiter is determined, processed and already enriched with the previous deleted delemiter. Anything left of the String is stored into another variable. Finally the last substring of the recursion does not contain a delimiter, so the function call is finished.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
 
    <xsl:template match="/cars">
 
        <xsl:choose>
 
            <xsl:when test="boolean(.)">
                <xsl:call-template name="substring-before-last">
                    <xsl:with-param name="list" select="normalize-space(.)"/>
                    <xsl:with-param name="delimiter" select="','"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise/>
 
        </xsl:choose>
 
    </xsl:template>
 
    <!--############################################################-->
    <!--## Template to determine Substring before last occurence  ##-->
    <!--## of a specific delemiter                                ##-->
    <!--############################################################-->
    <xsl:template name="substring-before-last">
	<!--passed template parameter -->
        <xsl:param name="list"/>
        <xsl:param name="delimiter"/>
        <xsl:choose>
            <xsl:when test="contains($list, $delimiter)">
		<!-- get everything in front of the first delimiter -->
                <xsl:value-of select="substring-before($list,$delimiter)"/>
                <xsl:choose>
                    <xsl:when test="contains(substring-after($list,$delimiter),$delimiter)">
                        <xsl:value-of select="$delimiter"/>
                    </xsl:when>
                </xsl:choose>
                <xsl:call-template name="substring-before-last">
                    <!-- store anything left in another variable -->
                    <xsl:with-param name="list" select="substring-after($list,$delimiter)"/>
                    <xsl:with-param name="delimiter" select="$delimiter"/>
                </xsl:call-template>
            </xsl:when>
        </xsl:choose>
    </xsl:template>
 
</xsl:stylesheet>

In case a given argument $arg contains initially no delemiter $delim nothing is returned and the template call is completed.

The extracted single value in this example can be further customized. The output after XSLT 1.0 transformation is the following:

Audi, Volkswagen, Skoda, Seat

You see, with a little extra effort it is possible to get a Substring for special cases also in XSL 1.0. And the advantage -> It is XSL standard behavior without any 3rd party libraries!


This entry was posted in XML, XSL and tagged , , . Bookmark the permalink.

One Response to Getting a substring before the last occurrence of a character in XSLT 1.0

  1. Linn Endresen says:

    Thanks, this solves my problem perfectly 🙂

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.