substring() Function  
Returns a portion of a given string. The second and third arguments determine what portion of the string is returned. The second argument specifies the position of the first character of the substring, and the optional third argument specifies how many characters should be returned.
 
Inputs

The substring() function takes a string and one or two numbers as arguments. The string is the string from which the substring will be extracted. The second argument is used as the starting position of the returned substring, and the optional third argument specifies how many characters are returned.

 
Output

With two arguments (a string and a starting position), the substring() function returns all characters in the string, starting with the starting position. Be aware that the first character in an XPath string is at position 1, not 0.

With three arguments (a string, a starting position, and a length), the substring() function returns all characters in the string whose position is greater than or equal to the starting position and whose position is less than or equal to the starting position plus the length.

Normally, the arguments to the substring() function are integers, although they may be more complicated expressions. See the "Example" section that follows for some unusual cases.

 
Defined in

XPath section 4.2, String Functions.

 
Example

We'll use this XML document to demonstrate how the substring() function works:

<?xml version="1.0"?>
<test>
  <p>This is a test XML document used by several 
    of our sample stylesheets.</p>
  <question>
    <text>When completed, the Eiffel Tower was the 
    tallest building in the world.</text>
    <true>You're correct!  The Eiffel Tower was the 
    world's tallest building until 1930.</true>

    <false>No, the Eiffel Tower was the world's 
    tallest building for over 30 years.</false>
  </question>
  <question>
    <text>New York's Empire State Building knocked the 
    Eiffel Tower from its pedestal.</text>
    <true>No, that's not correct.</true>
    <false>Correct!  New York's Chrysler Building, 
    completed in 1930, became the world's tallest.</false>
  </question>
</test>

Here's the stylesheet we'll use:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="text"/>

  <xsl:variable name="newline">
<xsl:text>
</xsl:text>
  </xsl:variable>

  <xsl:template match="/">
    <xsl:value-of select="$newline"/>
    <xsl:text>Tests of the substring() function:</xsl:text>

    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   substring('Now is the time', 4)="</xsl:text>
    <xsl:value-of select="substring('Now is the time', 4)"/>
    <xsl:text>"</xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:text>   substring('Now is the time', 4, 6)="</xsl:text>
    <xsl:value-of select="substring('Now is the time', 4, 6)"/>
    <xsl:text>"</xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:text>   substring('Now is the time', 4, -6)="</xsl:text>
    <xsl:value-of select="substring('Now is the time', 4, -6)"/>
    <xsl:text>"</xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:text>   substring('Now is the time', -3, 6)="</xsl:text>
    <xsl:value-of select="substring('Now is the time', -3, 6)"/>
    <xsl:text>"</xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:text>   substring('Now is the time', 54, 6)="</xsl:text>
    <xsl:value-of select="substring('Now is the time', 54, 6)"/>
    <xsl:text>"</xsl:text>

    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   count(//*)=</xsl:text>
    <xsl:value-of select="count(//*)"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   substring('Here is a really long string', </xsl:text> 
    <:xsl:text>count(//*))="</xsl:text>
    <xsl:value-of 
      select="substring('Here is a really long string', count(//*))"/>
    <xsl:text>"</xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:text>   substring('Here is a less long string', </xsl:text>
    <xsl:text>count(//*) mod 7, 7)="</xsl:text>
    <xsl:value-of 
      select="substring('Here is a less long string', count(//*) mod 7, 7)"/>
    <xsl:text>"</xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:text>   substring(/test/question[1]/text, 3, 7)="</xsl:text>
    <xsl:value-of select="substring(//*, 3, 7)"/>
    <xsl:text>"</xsl:text>
    <xsl:value-of select="$newline"/>
  </xsl:template>

</xsl:stylesheet>

When using the Saxon processor, here are the results:


Tests of the substring() function:

   substring('Now is the time', 4)=" is the time"
   substring('Now is the time', 4, 6)=" is th"
   substring('Now is the time', 4, -6)="
   substring('Now is the time', -3, 6)="No"
   substring('Now is the time', 54, 6)="

   count(//*)=10
   substring('Here is a really long string', count(//*))=" really long string"
   substring('Here is a less long string', count(//*) mod 7, 7)="re is a"
   substring(/test/question[1]/text, 3, 7)=" This i"

When running the same transformation with Xalan, we get a runtime error:

file:///D:/O'Reilly/XSLT/bookSamples/AppendixC/substringfunction.xsl; Line 26;
  Column 65;
Tests of the substring() function:


   substring('Now is the time', 4)=" is the time"
   substring('Now is the time', 4, 6)=" is th"
   substring('Now is the time', 4, -6)="
XSLT Error (javax.xml.transform.TransformerException): String index out of range
: -3

As of this writing, XT, Saxon, and Oracle's processors all gave the correct results; both Xalan and Microsoft's XSLT tools generated runtime exceptions. The lesson here is to use reasonable arguments to the substring() function so you won't be at the mercy of different implementations.