home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam  


Book HomeXSLTSearch this book

Appendix C. XSLT and XPath Function Reference

This section lists all functions defined by XSLT and XPath.

boolean() FunctionConverts its argument to a boolean value.

Synopsis

boolean boolean(object)

Inputs

An object. The object is converted to a boolean value. This conversion is described in the following subsection.

Output

The boolean value corresponding to the input object. Objects are converted to boolean values as follows:

  • A number is true if and only if it is not zero, negative zero, or NaN (not a number).

  • A node-set is true if and only if it is not empty.

  • A string is true if and only if its length is greater than zero.

  • All other datatypes are converted in a way specific to those datatypes.

Defined in

XPath section 4.3, Boolean Functions.

Example

The following example demonstrates the results of invoking the boolean() function against a variety of argument types. Here's our XML document:

<?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>Yes!  The Eiffel Tower was the world's 
tallest building until 1932, when
New York's Empire State Building opened. </true>
<false>No, the Eiffel Tower was the world's tallest 
building for over 30 years.</false>
</question>
</test>

We'll process this document with the following stylesheet:

<?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 boolean() function:</xsl:text>

    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:choose>
      <xsl:when test="boolean(true())">
        <xsl:text>   "boolean(true())"   returned true!</xsl:text>
      </xsl:when>
      <xsl:otherwise>
        <xsl:text>   "boolean(true())"   returned false!</xsl:text>
      </xsl:otherwise>
    </xsl:choose>

    <xsl:value-of select="$newline"/>
    <xsl:choose>
      <xsl:when test="boolean(true)">

        <xsl:text>   "boolean(true)"     returned true!</xsl:text>
      </xsl:when>
      <xsl:otherwise>
        <xsl:text>   "boolean(true)"     returned false!</xsl:text>
      </xsl:otherwise>
    </xsl:choose>

    <xsl:value-of select="$newline"/>
    <xsl:choose>
      <xsl:when test="boolean('false')">
        <xsl:text>   "boolean('false')"  returned true!</xsl:text>
      </xsl:when>
      <xsl:otherwise>
        <xsl:text>   "boolean('false')"  returned false!</xsl:text>
      </xsl:otherwise>
    </xsl:choose>

    <xsl:value-of select="$newline"/>
    <xsl:choose>
      <xsl:when test="boolean('7')">
        <xsl:text>   "boolean('7')"      returned true!</xsl:text>
      </xsl:when>
      <xsl:otherwise>
        <xsl:text>   "boolean('7')"      returned false!</xsl:text>
      </xsl:otherwise>
    </xsl:choose>

    <xsl:value-of select="$newline"/>
    <xsl:choose>
      <xsl:when test="boolean(/true)">
        <xsl:text>   "boolean(/true)"    returned true!</xsl:text>
      </xsl:when>
      <xsl:otherwise>
        <xsl:text>   "boolean(/true)"    returned false!</xsl:text>
      </xsl:otherwise>
    </xsl:choose>

    <xsl:value-of select="$newline"/>
    <xsl:choose>
      <xsl:when test="boolean(//true)">
        <xsl:text>   "boolean(//true)"   returned true!</xsl:text>
      </xsl:when>
      <xsl:otherwise>
        <xsl:text>   "boolean(//true)"   returned false!</xsl:text>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

Here are the results:


Tests of the boolean() function:

   "boolean(true())"   returned true!
   "boolean(true)"     returned false!
   "boolean('false')"  returned true!
   "boolean('7')"      returned true!
   "boolean(/true)"    returned false!
   "boolean(//true)"   returned true!

See Section 4.2.1.2, "Boolean examples" in Chapter 4, "Branching and Control Elements" for more examples and information.

ceiling() FunctionReturns the smallest integer that is not less than the argument.

Synopsis

number ceiling(number)

Inputs

A number. If the argument is not a number, it is transformed into a number as if it had been processed by the number() function. If the argument cannot be transformed into a number, the ceiling() function returns the value NaN (not a number).

Output

The smallest integer that is not less than the argument, or NaN if the argument cannot be converted to a number.

Defined in

XPath section 4.4, Number Functions.

Example

The following stylesheet shows the results of invoking the ceiling() function against a variety of values. We'll use this XML document as input:

<?xml version="1.0"?>
<report>
  <title>Miles Flown in 2001</title>
  <month sequence="01">
    <miles-flown>12379</miles-flown>
    <miles-earned>35215</miles-earned>
  </month>
  <month sequence="02">
    <miles-flown>32857</miles-flown>
    <miles-earned>92731</miles-earned>
  </month>
  <month sequence="03">
    <miles-flown>19920</miles-flown>
    <miles-earned>76725</miles-earned>
  </month>
  <month sequence="04">
    <miles-flown>18903</miles-flown>
    <miles-earned>31781</miles-earned>
  </month>
</report>

Here's the stylesheet that uses the ceiling() function:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:months="Lookup table for month names">

  <months:name sequence="01">January</months:name>
  <months:name sequence="02">February</months:name>
  <months:name sequence="03">March</months:name>
  <months:name sequence="04">April</months:name>
  <months:name sequence="05">May</months:name>
  <months:name sequence="06">June</months:name>
  <months:name sequence="07">July</months:name>
  <months:name sequence="08">August</months:name>
  <months:name sequence="09">September</months:name>
  <months:name sequence="10">October</months:name>
  <months:name sequence="11">November</months:name>
  <months:name sequence="12">December</months:name>

  <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 ceiling() function:</xsl:text>

    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   "ceiling('7.983')" = </xsl:text>
    <xsl:value-of select="ceiling('7.983')"/>

    <xsl:value-of select="$newline"/>
    <xsl:text>   "ceiling('-7.893')" = </xsl:text>
    <xsl:value-of select="ceiling('-7.893')"/>

    <xsl:value-of select="$newline"/>
    <xsl:text>   "ceiling(/report/month[@sequence='01']/miles-flown)" = </xsl:text>
    <xsl:value-of select="ceiling(/report/month[@sequence='01']/miles-flown)"/>

    <xsl:value-of select="$newline"/>
    <xsl:text>   "ceiling(document('')/*/</xsl:text>
    <xsl:text>months:name[@sequence='02'])" = </xsl:text>
    <xsl:value-of select="ceiling(document('')/*/months:name[@sequence='02'])"/>

    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:for-each select="/report/month">
      <xsl:text>   </xsl:text>
      <xsl:value-of 
        select="document('')/*/months:name[@sequence=current()/@sequence]"/>
      <xsl:text> - </xsl:text>
      <xsl:value-of select="format-number(miles-flown, '##,###')"/>
      <xsl:text> miles flown, </xsl:text>
      <xsl:value-of select="format-number(miles-earned, '##,###')"/>
      <xsl:text> miles earned.</xsl:text>
      <xsl:value-of select="$newline"/>
      <xsl:text>      (Averaged </xsl:text>
      <xsl:value-of select="ceiling(miles-earned div miles-flown)"/>
      <xsl:text> miles earned for each mile flown.)</xsl:text>
      <xsl:value-of select="$newline"/>
      <xsl:value-of select="$newline"/>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

When we transform the XML document with our stylesheet, here are the results:


Tests of the ceiling() function:

   "ceiling('7.983')" = 8
   "ceiling('-7.893')" = -7
   "ceiling(/report/month[@sequence='01']/miles-flown)" = 12379
   "ceiling(document('')/*/months:name[@sequence='02'])" = NaN

   January - 12,379 miles flown, 35,215 miles earned.
      (Averaged 3 miles earned for each mile flown.)

   February - 32,857 miles flown, 92,731 miles earned.
      (Averaged 3 miles earned for each mile flown.)

   March - 19,920 miles flown, 76,725 miles earned.
      (Averaged 4 miles earned for each mile flown.)

   April - 18,903 miles flown, 31,781 miles earned.
      (Averaged 2 miles earned for each mile flown.)

Notice that when we invoked the ceiling() function against the string "February" (what document('')/*/months:name[@sequence='02'] resolves to), the function returned NaN. You can compare these results to those from the floor() function and the round() function.

concat() FunctionTakes all of its arguments and concatenates them. Any arguments that are not strings are converted to strings as if processed by the string() function.

Synopsis

string concat(stringstringstring*)

Inputs

Two or more strings.

Output

The concatenation of all of the input strings.

Defined in

XPath section 4.2, String Functions.

Example

We'll use this XML file to demonstrate how concat() works:

<?xml version="1.0"?>
<list>
  <title>A few of my favorite albums</title>
  <listitem>A Love Supreme</listitem>
  <listitem>Beat Crazy</listitem>
  <listitem>Here Come the Warm Jets</listitem>
  <listitem>Kind of Blue</listitem>
  <listitem>London Calling</listitem>
  <listitem>Remain in Light</listitem>
  <listitem>The Joshua Tree</listitem>
  <listitem>The Indestructible Beat of Soweto</listitem>
</list>

In our stylesheet, we'll use the concat() function to create filenames for various JPEG files. The filenames are composed from several pieces of information, concatenated by the concat() function:

<?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:for-each select="list/listitem">
      <xsl:text>See the file </xsl:text>
      <xsl:value-of select="concat('album', position(), '.jpg')"/>
      <xsl:text> to see the title of album #</xsl:text>
      <xsl:value-of select="position()"/>
      <xsl:value-of select="$newline"/>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

Our stylesheet generates these results:


See the file album1.jpg to see the title of album #1
See the file album2.jpg to see the title of album #2
See the file album3.jpg to see the title of album #3
See the file album4.jpg to see the title of album #4
See the file album5.jpg to see the title of album #5
See the file album6.jpg to see the title of album #6
See the file album7.jpg to see the title of album #7
See the file album8.jpg to see the title of album #8
contains() FunctionDetermines if the first argument string contains the second.

Synopsis

boolean contains(stringstring)

Inputs

Two strings. If the first string contains the second string, the function returns the boolean value true.

Output

The boolean value true if the first argument contains the second; false otherwise.

Defined in

XPath section 4.2, String Functions.

Example

This stylesheet uses the replace-substring named template. It passes three arguments to the replace-substring template: the original string, the substring to be searched for in the original string, and the substring to replace the target substring in the original string. The replace-substring template uses the contains(), substring-after(), and substring-before() functions extensively.

Here is our sample stylesheet. It replaces all occurrences of World with the string "Mundo":

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

  <xsl:output method="text"/>

  <xsl:template match="/">
    <xsl:variable name="test">
      <xsl:call-template name="replace-substring">
        <xsl:with-param name="original">Hello World!</xsl:with-param>
        <xsl:with-param name="substring">World</xsl:with-param>
        <xsl:with-param name="replacement">Mundo</xsl:with-param>
      </xsl:call-template>
    </xsl:variable>
    <xsl:value-of select="$test"/>
  </xsl:template>

  <xsl:template name="replace-substring">
    <xsl:param name="original"/>
    <xsl:param name="substring"/>
    <xsl:param name="replacement" select="''"/>
    <xsl:variable name="first">
      <xsl:choose>
        <xsl:when test="contains($original, $substring)">
          <xsl:value-of select="substring-before($original, $substring)"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="$original"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <xsl:variable name="middle">
      <xsl:choose>
        <xsl:when test="contains($original, $substring)">
          <xsl:value-of select="$replacement"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:text></xsl:text>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <xsl:variable name="last">
      <xsl:choose>
        <xsl:when test="contains($original, $substring)">
          <xsl:choose>
            <xsl:when test="contains(substring-after($original, 
                                        $substring), $substring)">
              <xsl:call-template name="replace-substring">
                <xsl:with-param name="original">
                  <xsl:value-of 
                    select="substring-after($original, $substring)"/>
                </xsl:with-param>
                <xsl:with-param name="substring">
                  <xsl:value-of select="$substring"/>
                </xsl:with-param>
                <xsl:with-param name="replacement">
                  <xsl:value-of select="$replacement"/>
                </xsl:with-param>
              </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of 
                select="substring-after($original, $substring)"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:when>
        <xsl:otherwise>
          <xsl:text></xsl:text>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <xsl:value-of select="concat($first, $middle, $last)"/>
  </xsl:template>

</xsl:stylesheet>

The stylesheet produces these results, regardless of the XML document used as input:

Hello Mundo!
count() FunctionCounts the number of nodes in a given node-set.

Synopsis

number count(node-set)

Inputs

A node-set.

Output

The number of nodes in the node-set.

Defined in

XPath section 4.1, Node Set Functions.

Examples

Here's the XML document we'll use to illustrate the count() function:

<?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 a stylesheet that illustrates the count() function:

<?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 count() function:</xsl:text>

    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   count(/test)=</xsl:text>
    <xsl:value-of select="count(/test)"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   count(/true)=</xsl:text>
    <xsl:value-of select="count(/true)"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   count(//true)=</xsl:text>
    <xsl:value-of select="count(//true)"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   count(//test|//true|//text)=</xsl:text>
    <xsl:value-of select="count(//test|//true|//text)"/>
    <xsl:value-of select="$newline"/>
    <xsl:variable name="numberOfQuestions" select="count(/test/question)"/>
    <xsl:for-each select="/test/question">
      <xsl:text>   This is question number </xsl:text>
      <xsl:value-of select="position()"/>
      <xsl:text> of </xsl:text>
      <xsl:value-of select="$numberOfQuestions"/>

      <xsl:value-of select="$newline"/>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

Here are the results of our stylesheet:


Tests of the count() function:

   count(/test)=1
   count(/true)=0
   count(//true)=2
   count(//test|//true|//text)=5
   This is question number 1 of 2
   This is question number 2 of 2

The first four invocations of the count() function merely use XPath expressions to count something in the XML document. The last use of count() counts the number of <question> elements in our document and stores that value in a variable. Generating text like "item x of y" is a common technique; our use of the count() and position() is how this generation is commonly done.

current() FunctionReturns a node-set that has the current node as its only member.

Synopsis

node-set current()

Inputs

None.

Output

A node-set that has the current node as its only member. Most of the time, the current node is no different than the context node. These two XSLT elements have the same meaning:

<xsl:value-of select="current()"/>
<xsl:value-of select="."/>

Within a predicate expression, however, the current node and the context node are usually different. The example section that follows illustrates when you need to use the current() function.

Defined in

XSLT section 12.4, Miscellaneous Additional Functions.

Example

We'll use the current() function along with a lookup table. Here's the document we'll transform:

<?xml version="1.0"?>
<report>
  <title>Miles Flown in 2001</title>
  <month sequence="01">
    <miles-flown>12379</miles-flown>
    <miles-earned>35215</miles-earned>
  </month>
  <month sequence="02">
    <miles-flown>32857</miles-flown>
    <miles-earned>92731</miles-earned>
  </month>
  <month sequence="03">
    <miles-flown>19920</miles-flown>
    <miles-earned>76725</miles-earned>
  </month>
  <month sequence="04">
    <miles-flown>18903</miles-flown>
    <miles-earned>31781</miles-earned>
  </month>
</report>

Here's our stylesheet. We'll do the same transform twice, one time with the current() function and one time without it:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:months="Lookup table for month names">

  <months:name sequence="12">December</months:name>
  <months:name sequence="01">January</months:name>
  <months:name sequence="02">February</months:name>
  <months:name sequence="03">March</months:name>
  <months:name sequence="04">April</months:name>
  <months:name sequence="05">May</months:name>
  <months:name sequence="06">June</months:name>
  <months:name sequence="07">July</months:name>
  <months:name sequence="08">August</months:name>
  <months:name sequence="09">September</months:name>
  <months:name sequence="10">October</months:name>
  <months:name sequence="11">November</months:name>

  <xsl:output method="text"/>


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

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

    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:for-each select="/report/month">
      <xsl:text>   </xsl:text>
      <xsl:value-of 
        select="document('')/*/months:name[@sequence=current()/@sequence]"/>
      <xsl:text> - </xsl:text>
      <xsl:value-of select="format-number(miles-flown, '##,###')"/>
      <xsl:text> miles flown, </xsl:text>
      <xsl:value-of select="format-number(miles-earned, '##,###')"/>
      <xsl:text> miles earned.</xsl:text>
      <xsl:value-of select="$newline"/>
      <xsl:text>      (Averaged </xsl:text>
      <xsl:value-of 
        select="format-number(miles-earned div miles-flown, '##.#')"/>
      <xsl:text> miles earned for each mile flown.)</xsl:text>
      <xsl:value-of select="$newline"/>
      <xsl:value-of select="$newline"/>
    </xsl:for-each>
    <xsl:value-of select="$newline"/>

    <xsl:text>Let's try it again, without using current() this time:</xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>

    <xsl:for-each select="/report/month">
      <xsl:text>   </xsl:text>
      <xsl:value-of 
        select="document('')/*/months:name[@sequence=./@sequence]"/>
      <xsl:text> - </xsl:text>
      <xsl:value-of select="format-number(miles-flown, '##,###')"/>
      <xsl:text> miles flown, </xsl:text>
      <xsl:value-of select="format-number(miles-earned, '##,###')"/>
      <xsl:text> miles earned.</xsl:text>
      <xsl:value-of select="$newline"/>
      <xsl:text>      (Averaged </xsl:text>
      <xsl:value-of 
        select="format-number(miles-earned div miles-flown, '##.#')"/>
      <xsl:text> miles earned for each mile flown.)</xsl:text>

      <xsl:value-of select="$newline"/>
      <xsl:value-of select="$newline"/>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

Here are the results:


A test of the current() function:

   January - 12,379 miles flown, 35,215 miles earned.
      (Averaged 2.8 miles earned for each mile flown.)

   February - 32,857 miles flown, 92,731 miles earned.
      (Averaged 2.8 miles earned for each mile flown.)

   March - 19,920 miles flown, 76,725 miles earned.
      (Averaged 3.9 miles earned for each mile flown.)

   April - 18,903 miles flown, 31,781 miles earned.
      (Averaged 1.7 miles earned for each mile flown.)


Let's try it again, without using current() this time:

   December - 12,379 miles flown, 35,215 miles earned.
      (Averaged 2.8 miles earned for each mile flown.)

   December - 32,857 miles flown, 92,731 miles earned.
      (Averaged 2.8 miles earned for each mile flown.)

   December - 19,920 miles flown, 76,725 miles earned.
      (Averaged 3.9 miles earned for each mile flown.)

   December - 18,903 miles flown, 31,781 miles earned.
      (Averaged 1.7 miles earned for each mile flown.)

The second time around, our stylesheet matched each <month> element to the month December. The difference is that the dot syntax (.) represents the current node at that point in the XPath expression, while the current() function represents the current node before the XSLT processor began evaluating the XPath expression.

In other words, the XSLT processor starts with the first <months:name> element, attempting to find the element whose sequence attribute matches another sequence attribute we're examining. If we specify the other sequence attribute with ./@sequence, it indicates the sequence attribute of the current node at this point in the expression, which is the first <months:name> element. That always returns the value of the first <months:name> element. Using the current() function, on the other hand, returns the node that was current when we started to evaluate this expression; current() gives us the behavior we want.

document() FunctionAllows you to process multiple source documents in a single stylesheet. This extremely powerful and flexible function is the subject of , so we'll only include a brief overview of the function here.

Synopsis

node-set document(objectnode-set?)

Inputs

The document() function most commonly takes a string as its argument; that string is treated as a URI, and the XSLT processor attempts to open that URI and parse it. If the string is empty (the function call is document('')), the document() function parses the stylesheet itself. See Section 7.3, "Invoking the document() Function" in Chapter 7, "Combining XML Documents" for all the details on the parameters to the document() function.

Output

A node-set containing the nodes identified by the input argument. Again, Chapter 7, "Combining XML Documents" has all the details, so we won't rehash them here.

Defined in

XSLT section 12.1, Multiple Source Documents.

Example

The following example uses the document() function with an empty string to implement a lookup table. Here is our XML document:

<?xml version="1.0"?>
<report>
  <title>Miles Flown in 2001</title>
  <month sequence="01">
    <miles-flown>12379</miles-flown>
    <miles-earned>35215</miles-earned>
  </month>
  <month sequence="02">
    <miles-flown>32857</miles-flown>
    <miles-earned>92731</miles-earned>
  </month>
  <month sequence="03">
    <miles-flown>19920</miles-flown>
    <miles-earned>76725</miles-earned>
  </month>
  <month sequence="04">
    <miles-flown>18903</miles-flown>
    <miles-earned>31781</miles-earned>
  </month>
</report>

We can use the document() function to convert the sequence attribute of the <month> element into the name of the corresponding month. Here is our stylesheet:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:months="Lookup table for month names">

  <months:name sequence="01">January</months:name>
  <months:name sequence="02">February</months:name>
  <months:name sequence="03">March</months:name>
  <months:name sequence="04">April</months:name>
  <months:name sequence="05">May</months:name>
  <months:name sequence="06">June</months:name>
  <months:name sequence="07">July</months:name>
  <months:name sequence="08">August</months:name>
  <months:name sequence="09">September</months:name>
  <months:name sequence="10">October</months:name>
  <months:name sequence="11">November</months:name>
  <months:name sequence="12">December</months:name>

  <xsl:output method="text"/>

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

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

    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:for-each select="/report/month">
      <xsl:text>   </xsl:text>
      <xsl:value-of 
        select="document('')/*/months:name[@sequence=current()/@sequence]"/>
      <xsl:text> - </xsl:text>
      <xsl:value-of select="format-number(miles-flown, '##,###')"/>
      <xsl:text> miles flown, </xsl:text>
      <xsl:value-of select="format-number(miles-earned, '##,###')"/>
      <xsl:text> miles earned.</xsl:text>
      <xsl:value-of select="$newline"/>
      <xsl:text>      (Averaged </xsl:text>
      <xsl:value-of 
        select="format-number(miles-earned div miles-flown, '##.#')"/>
      <xsl:text> miles earned for each mile flown.)</xsl:text>

      <xsl:value-of select="$newline"/>
      <xsl:value-of select="$newline"/>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

Here are the results, with the correct month names included in the output:


A test of the document() function:

   January - 12,379 miles flown, 35,215 miles earned.
      (Averaged 2.8 miles earned for each mile flown.)

   February - 32,857 miles flown, 92,731 miles earned.
      (Averaged 2.8 miles earned for each mile flown.)

   March - 19,920 miles flown, 76,725 miles earned.
      (Averaged 3.9 miles earned for each mile flown.)

   April - 18,903 miles flown, 31,781 miles earned.
      (Averaged 1.7 miles earned for each mile flown.)
element-available() FunctionDetermines if a given element is available to the XSLT processor. This function allows you to design stylesheets that react gracefully if a particular element is not available to process an XML document.

Synopsis

boolean element-available(string)

Inputs

The element's name. The name should be qualified with a namespace; if the namespace URI is the same as the XSLT namespace URI, then the element name refers to an element defined by XSLT. Otherwise, the name refers to an extension element. If the element name has a null namespace URI, then the element-available function returns false.

Output

The boolean value true if the element is available; false otherwise.

Defined in

XSLT section 15, Fallback.

Example

We'll use the following example to test the element-available() function:

<?xml version="1.0"?>
<book>
  <title>XSLT</title>
  <chapter>
    <title>Getting Started</title>
    <para>If this chapter had any text, it would appear here.</para>
  </chapter>
  <chapter>
    <title>The Hello World Example</title>
    <para>If this chapter had any text, it would appear here.</para>
  </chapter>
  <chapter>
    <title>XPath</title>
    <para>If this chapter had any text, it would appear here.</para>
  </chapter>
  <chapter>
    <title>Stylesheet Basics</title>
    <para>If this chapter had any text, it would appear here.</para>
  </chapter>
  <chapter>
    <title>Branching and Control Elements</title>
    <para>If this chapter had any text, it would appear here.</para>
  </chapter>
  <chapter>
    <title>Functions</title>
    <para>If this chapter had any text, it would appear here.</para>
  </chapter>
  <chapter>
    <title>Creating Links and Cross-References</title>
    <para>If this chapter had any text, it would appear here.</para>
  </chapter>
  <chapter>
    <title>Sorting and Grouping Elements</title>
    <para>If this chapter had any text, it would appear here.</para>
  </chapter>
  <chapter>
    <title>Combining XML Documents</title>
    <para>If this chapter had any text, it would appear here.</para>
  </chapter>
</book>

Here is our stylesheet:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:redirect="org.apache.xalan.xslt.extensions.Redirect"

  xmlns:saxon="http://icl.com/saxon"
  extension-element-prefixes="redirect saxon">

  <xsl:output method="html"/>

  <xsl:template match="/">
    <xsl:choose>
      <xsl:when test="element-available('redirect:write')">
        <xsl:for-each select="/book/chapter">
          <redirect:write select="concat('chapter', position(), '.html')">
            <html>
              <head>
                <title><xsl:value-of select="title"/></title>
              </head>
              <body>
                <h1><xsl:value-of select="title"/></h1>
                <xsl:apply-templates select="para"/>
                <xsl:if test="not(position()=1)">
                  <p>
                    <a href="chapter{position()-1}.html">Previous</a>
                  </p>
                </xsl:if>
                <xsl:if test="not(position()=last())">
                  <p>
                    <a href="chapter{position()+1}.html">Next</a>
                  </p>
                </xsl:if>
              </body>
            </html>
          </redirect:write>
        </xsl:for-each>
      </xsl:when>
      <xsl:when test="element-available('saxon:output')">
        <xsl:for-each select="/book/chapter">
          <saxon:output file="chapter{position()}.html">
            <html>
              <head>
                <title><xsl:value-of select="title"/></title>
              </head>
              <body>
                <h1><xsl:value-of select="title"/></h1>
                <xsl:apply-templates select="para"/>
                <xsl:if test="not(position()=1)">
                  <p>
                    <a href="chapter{position()-1}.html">Previous</a>
                  </p>
                </xsl:if>
                <xsl:if test="not(position()=last())">

                  <p>
                    <a href="chapter{position()+1}.html">Next</a>
                  </p>
                </xsl:if>
              </body>
            </html>
          </saxon:output>
        </xsl:for-each>
      </xsl:when>
      <xsl:otherwise>
        <html>
          <head>
            <title><xsl:value-of select="/book/title"/></title>
          </head>
          <xsl:for-each select="/book/chapter">
            <h1><xsl:value-of select="title"/></h1>
            <xsl:apply-templates select="para"/>
          </xsl:for-each>
        </html>
      </xsl:otherwise>
    </xsl:choose>
    <xsl:if test="not(element-available('write'))">
      <xsl:message terminate="no">
        The <write> element is not available!
      </xsl:message>
    </xsl:if>
  </xsl:template>

  <xsl:template match="para">
    <p><xsl:apply-templates select="*|text()"/></p>
  </xsl:template>

</xsl:stylesheet>

This stylesheet attempts to take the content in the XML file and write portions of it out to different HTML files. The first <chapter> element is written to the file chapter1.html, the second <chapter> element is written to the file chapter2.html, and so on. Our stylesheet attempts to use Xalan's <redirect:write> element first; if that element is not available, it checks for Saxon's <saxon:output> element. If neither of those elements is available, it writes the contents of all <chapter> elements to the same output stream. The stylesheet also calls the element-available() function with the nonqualified element name write; this call always returns false because the element name is not namespace qualified.

When we use Xalan to process the XML file with our stylesheet, here are the results on the console:

file:///D:/O'Reilly/XSLT/bookSamples/AppendixC/elementavailable.xsl; Line 66; 
Column 35; The <write> element is not available!

The stylesheet generates the files chapter1.html through chapter9.html, with each file containing data from one of the <chapter> elements in the original file. Our stylesheet also generates hyperlinks between the chapter files; here's what chapter3.html looks like:

<html>
   <head>
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
   
      <title>XPath</title>
   </head>
   <body>
      <h1>XPath</h1>
      <p>If this chapter had any text, it would appear here.</p>
      <p><a href="chapter2.html">Previous</a></p>
      <p><a href="chapter4.html">Next</a></p>
   </body>
</html>

When rendered in a browser, the file looks like Figure C-1.

Figure C-1

Figure C-1. Sample HTML output file

Clicking on the Previous link takes you to the file chapter2.html, while clicking on the Next link takes you to chapter4.html.

Using our stylesheet with Saxon (using the command java com.icl.saxon.StyleSheet chapterlist.xml elementavailable.xsl) produces similar results on the console:

The <write> element is not available!

Although the format of the message is slightly different, the output in the multiple HTML files is the same.

Finally, if we use the Oracle XML parser, none of the elements we query will be available, so all the output is written to a single file. We'll invoke the processor with this command. (The command should be on one line.)

java oracle.xml.parser.v2.oraxsl chapterlist.xml 
  elementavailable.xsl chapters.html

Here's the console output:

Message: The <write> element is not available!

The output file, chapters.html, looks like this:

<html xmlns:redirect="org.apache.xalan.xslt.extensions.Redirect" 
  xmlns:saxon="http://icl.com/saxon">
   <head>
      <META http-equiv="Content-Type" content="text/html">
      <title>XSLT</title>
   </head>
   <h1>Getting Started</h1>
   <p>If this chapter had any text, it would appear here.</p>
   <h1>The Hello World Example</h1>
   <p>If this chapter had any text, it would appear here.</p>
   <h1>XPath</h1>
   <p>If this chapter had any text, it would appear here.</p>
   <h1>Stylesheet Basics</h1>
   <p>If this chapter had any text, it would appear here.</p>
   <h1>Branching and Control Elements</h1>
   <p>If this chapter had any text, it would appear here.</p>
   <h1>Functions</h1>
   <p>If this chapter had any text, it would appear here.</p>
   <h1>Creating Links and Cross-References</h1>
   <p>If this chapter had any text, it would appear here.</p>
   <h1>Sorting and Grouping Elements</h1>
   <p>If this chapter had any text, it would appear here.</p>
   <h1>Combining XML Documents</h1>
   <p>If this chapter had any text, it would appear here.</p>
</html>

When rendered, our output looks like Figure C-2.

Figure C-2

Figure C-2. HTML document listing all chapters

In this example, the element-available() function allows us to determine what processing capabilities are available and respond gracefully to whatever we find.

false() FunctionAlways returns the boolean value false. Remember that the strings "true" and "false" don't have any special significance in XSLT. This function (and the true() function) allow you to generate boolean values directly when you need them.

Synopsis

boolean false()

Inputs

None.

Output

The boolean value false.

Defined in

XPath section 4.3, Boolean Functions.

Example

Here's a brief example that uses the false() function:

<?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>A test of the false() function:</xsl:text>

    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:choose>
      <xsl:when test="false()">
        <xsl:text>   "false()"   returned true!</xsl:text>
      </xsl:when>
      <xsl:otherwise>
        <xsl:text>   "false()"   returned false!</xsl:text>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

When using this stylesheet against any XML document, it generates this less-than-exciting result:


A test of the false() function:

   "false()"   returned false!
floor() FunctionReturns the largest integer that is not greater than the argument.

Synopsis

number floor(number)

Inputs

A number. If the argument is not a number, it is transformed into a number as if it had been processed by the number() function. If the argument cannot be transformed into a number, the floor() function returns NaN (not a number).

Output

The largest integer that is not greater than the argument, or NaN if the argument cannot be converted into a number.

Defined in

XPath section 4.4, Number Functions.

Example

The following stylesheet shows the results of invoking the floor() function against a variety of values. We'll use this XML document as input:

<?xml version="1.0"?>
<report>
  <title>Miles Flown in 2001</title>
  <month sequence="01">
    <miles-flown>12379</miles-flown>
    <miles-earned>35215</miles-earned>
  </month>
  <month sequence="02">
    <miles-flown>32857</miles-flown>
    <miles-earned>92731</miles-earned>
  </month>
  <month sequence="03">
    <miles-flown>19920</miles-flown>
    <miles-earned>76725</miles-earned>
  </month>
  <month sequence="04">
    <miles-flown>18903</miles-flown>
    <miles-earned>31781</miles-earned>
  </month>
</report>

Here's the stylesheet that uses the floor() function:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:months="Lookup table for month names">

  <months:name sequence="01">January</months:name>
  <months:name sequence="02">February</months:name>
  <months:name sequence="03">March</months:name>
  <months:name sequence="04">April</months:name>
  <months:name sequence="05">May</months:name>
  <months:name sequence="06">June</months:name>
  <months:name sequence="07">July</months:name>
  <months:name sequence="08">August</months:name>
  <months:name sequence="09">September</months:name>
  <months:name sequence="10">October</months:name>
  <months:name sequence="11">November</months:name>
  <months:name sequence="12">December</months:name>

  <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 floor() function:</xsl:text>

    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   "floor('7.983')" = </xsl:text>
    <xsl:value-of select="floor('7.983')"/>

    <xsl:value-of select="$newline"/>
    <xsl:text>   "floor('-7.893')" = </xsl:text>
    <xsl:value-of select="floor('-7.893')"/>

    <xsl:value-of select="$newline"/>
    <xsl:text>   "floor(/report/month[@sequence='01']</xsl:text>
    <xsl:text>/miles-flown)" = </xsl:text>
    <xsl:value-of select="floor(/report/month[@sequence='01']/miles-flown)"/>

    <xsl:value-of select="$newline"/>
    <xsl:text>   "floor(document('')/*/months:name</xsl:text>
    <xsl:text>[@sequence='02'])" = </xsl:text>
    <xsl:value-of select="floor(document('')/*/months:name[@sequence='02'])"/>

    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:for-each select="/report/month">
      <xsl:text>   </xsl:text>
      <xsl:value-of 
        select="document('')/*/months:name[@sequence=current()/@sequence]"/>
      <xsl:text> - </xsl:text>
      <xsl:value-of select="format-number(miles-flown, '##,###')"/>
      <xsl:text> miles flown, </xsl:text>
      <xsl:value-of select="format-number(miles-earned, '##,###')"/>
      <xsl:text> miles earned.</xsl:text>
      <xsl:value-of select="$newline"/>
      <xsl:text>      (Averaged </xsl:text>
      <xsl:value-of select="floor(miles-earned div miles-flown)"/>
      <xsl:text> miles earned for each mile flown.)</xsl:text>
      <xsl:value-of select="$newline"/>
      <xsl:value-of select="$newline"/>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

Here is the output of our stylesheet:


Tests of the floor() function:

   "floor('7.983')" = 7
   "floor('-7.893')" = -8
   "floor(/report/month[@sequence='01']/miles-flown)" = 12379
   "floor(document('')/*/months:name[@sequence='02'])" = NaN

   January - 12,379 miles flown, 35,215 miles earned.
      (Averaged 2 miles earned for each mile flown.)

   February - 32,857 miles flown, 92,731 miles earned.
      (Averaged 2 miles earned for each mile flown.)

   March - 19,920 miles flown, 76,725 miles earned.
      (Averaged 3 miles earned for each mile flown.)

   April - 18,903 miles flown, 31,781 miles earned.
      (Averaged 1 miles earned for each mile flown.)

Notice that when we invoked the ceiling() function against the string "February" (that's what document('')/*/months:name[@sequence='02'] resolves to), the function returned NaN. You can compare these results to those from the ceiling() function and the round() function.

format-number() FunctionTakes a number and formats it as a string.

Synopsis

string format-number(numberstringstring?)

Inputs

The number to be formatted and the format pattern string are required. The third argument is the optional name of a decimal format; if the third argument is not supplied, the default decimal format is used.

Output

The number, formatted according to the rules supplied by the other arguments. The special characters used in the second argument are:

#
Represents a digit. Trailing or leading zeroes are not displayed. Formatting the number 4.0 with the string "#.##" returns the string "4".

0
Represents a digit. Unlike the # character, the 0 always displays a zero. Formatting the number 4.1 with the string "#.00" returns the string "4.10".

.
Represents the decimal point.

-
Represents the minus sign.

,
Is the grouping separator.

;
Separates the positive-number pattern from the negative-number pattern.

%
Indicates that a number should be displayed as a percentage. The value will be multiplied by 100, then displayed as a percentage. Formatting the number .76 with the string "##%" returns the string "76%".

\u2030
Is the Unicode character for the per-thousand (per-mille) sign. The value will be multiplied by 1000, then displayed as a per mille. Formatting the number .768 with the string "###\u2030" returns the string "768Figure C.11".

The third argument, if given, must be the name of an <xsl:decimal-format> element. The <xsl:decimal-format> element lets you define the character that should be used for the decimal point and the grouping separator, the string used to represent infinity, and other formatting options. See Reference A.10 for more information.

Defined in

XSLT section 12.3, Number Formatting.

Example

The following stylesheet uses the format-number() function in various ways:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:months="Lookup table for month names">

  <xsl:output method="text"/>

  <months:name sequence="01">January</months:name>
  <months:name sequence="02">February</months:name>
  <months:name sequence="03">March</months:name>
  <months:name sequence="04">April</months:name>

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


  <xsl:decimal-format name="f1"
    decimal-separator=":"
    grouping-separator="/"/>

  <xsl:decimal-format name="f2"
    infinity="Really, really big"
    NaN="[not a number]"/>

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

    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   format-number(528.3, '#.#;-#.#')=</xsl:text>
    <xsl:value-of select="format-number(528.3, '#.#;-#.#')"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   format-number(528.3, '0,000.00;-0,000.00')=</xsl:text>
    <xsl:value-of select="format-number(528.3, '0,000.00;-0,000.00')"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   format-number(-23528.3, '$#,###.00;($#,###.00)')=</xsl:text>
    <xsl:value-of select="format-number(-23528.3, '$#,###.00;($#,###.00)')"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   format-number(1528.3, '#/###:00', 'f1')=</xsl:text>
    <xsl:value-of select="format-number(1528.3, '#/###:00;-#/###:00', 'f1')"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   format-number(1 div 0, '###,###.00', 'f2')=</xsl:text>
    <xsl:value-of select="format-number(1 div 0, '###,###.00', 'f2')"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   format-number(blue div orange, '#.##', 'f2')=</xsl:text>
    <xsl:value-of select="format-number(blue div orange, '#.##', 'f2')"/>
    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:for-each select="report/month">
      <xsl:text>   </xsl:text>
      <xsl:value-of 
        select="document('')/*/months:name[@sequence=current()/@sequence]"/>
      <xsl:text> - </xsl:text>
      <xsl:value-of select="format-number(miles-flown, '##,###')"/>
      <xsl:text> miles flown, </xsl:text>
      <xsl:value-of select="format-number(miles-earned, '##,###')"/>
      <xsl:text> miles earned.</xsl:text>
      <xsl:value-of select="$newline"/>
      <xsl:text>     (</xsl:text>
      <xsl:value-of 
        select="format-number(miles-flown div sum(//miles-flown), '##%')"/>
      <xsl:text> of all miles flown, </xsl:text>
      <xsl:value-of 
        select="format-number(miles-earned div sum(//miles-earned), '##%')"/>
      <xsl:text> of all miles earned.)</xsl:text>
      <xsl:value-of select="$newline"/>
      <xsl:value-of select="$newline"/>
    </xsl:for-each> 
    <xsl:text>   Total miles flown: </xsl:text>
    <xsl:value-of select="format-number(sum(//miles-flown), '##,###')"/>
    <xsl:text>, total miles earned: </xsl:text>
    <xsl:value-of select="format-number(sum(//miles-earned), '##,###')"/>
  </xsl:template>

</xsl:stylesheet>

We'll use this XML document with our stylesheet:

<?xml version="1.0"?>
<report>
  <title>Miles Flown in 2001</title>
  <month sequence="01">
    <miles-flown>12379</miles-flown>
    <miles-earned>35215</miles-earned>
  </month>
  <month sequence="02">
    <miles-flown>32857</miles-flown>
    <miles-earned>92731</miles-earned>
  </month>
  <month sequence="03">
    <miles-flown>19920</miles-flown>
    <miles-earned>76725</miles-earned>
  </month>
  <month sequence="04">
    <miles-flown>18903</miles-flown>
    <miles-earned>31781</miles-earned>
  </month>
</report>

When we run this stylesheet, here are the results:


Tests of the format-number() function:

   format-number(528.3, '#.#;-#.#')=528.3
   format-number(528.3, '0,000.00;-0,000.00')=0,528.30
   format-number(-23528.3, '$#,###.00;($#,###.00)')=($23,528.30)
   format-number(1528.3, '#/###:00', 'f1')=1/528:30
   format-number(1 div 0, '###,###.00', 'f2')=Really, really big
   format-number(blue div orange, '#.##', 'f2')=[not a number]

   January - 12,379 miles flown, 35,215 miles earned.
     (15% of all miles flown, 15% of all miles earned.)

   February - 32,857 miles flown, 92,731 miles earned.
     (39% of all miles flown, 39% of all miles earned.)

   March - 19,920 miles flown, 76,725 miles earned.
     (24% of all miles flown, 32% of all miles earned.)

   April - 18,903 miles flown, 31,781 miles earned.
     (22% of all miles flown, 13% of all miles earned.)

   Total miles flown: 84,059, total miles earned: 236,452

The first few examples illustrate some of the more complicated formatting options available, along with references to the <xsl:decimal-format> elements in the stylesheet. The last section is a more typical use of the format-number function: formatting values selected or calculated from an XML document.

function-available() FunctionDetermines if a given function is available to the XSLT processor. This function allows you to design stylesheets that react gracefully if a particular function is not available to process an XML document.

Synopsis

boolean function-available(string)

Inputs

The name function's name. The name is usually qualified with a namespace; if the namespace of the function name is non-null, the function is an extension function. Otherwise, the function is one of the functions defined in the XSLT or XPath specifications.

Output

The boolean value true if the function is available, false otherwise.

Defined in

XSLT section 15, Fallback.

Example

We'll use the following XML document to test the function-available() function:

<?xml version="1.0"?>
<list>
  <title>A few of my favorite albums</title>
  <listitem>A Love Supreme</listitem>
  <listitem>Beat Crazy</listitem>
  <listitem>Here Come the Warm Jets</listitem>
  <listitem>Kind of Blue</listitem>
  <listitem>London Calling</listitem>
  <listitem>Remain in Light</listitem>

  <listitem>The Joshua Tree</listitem>
  <listitem>The Indestructible Beat of Soweto</listitem>
</list>

Here's our stylesheet:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:jpeg="class:JPEGWriter"
  extension-element-prefixes="jpeg">

  <xsl:output method="text"/>

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

  <xsl:template match="/">
    <xsl:value-of select="$newline"/>
    <xsl:for-each select="list/listitem">
      <xsl:choose>
        <xsl:when test="function-available('jpeg:createJPEG')"> 
          <xsl:value-of 
            select="jpeg:createJPEG(., 'bg.jpg', 
            concat('album', position(), '.jpg'), 
            'Swiss 721 Bold Condensed', 'BOLD', 22, 52, 35)"/>
          <xsl:text>See the file </xsl:text>
          <xsl:value-of select="concat('album', position(), '.jpg')"/>
          <xsl:text> to see the title of album #</xsl:text>
          <xsl:value-of select="position()"/>
          <xsl:value-of select="$newline"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="position()"/>
          <xsl:text>. </xsl:text>
          <xsl:value-of select="."/>
          <xsl:value-of select="$newline"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

In our stylesheet, if the createJPEG() function is available, we'll invoke it to create JPEG files for the titles of all our favorite albums. If the function is not available, we'll simply write those titles to the output stream. Here are the results we get when the createJPEG() function is available:


See the file album1.jpg to see the title of album #1
See the file album2.jpg to see the title of album #2
See the file album3.jpg to see the title of album #3
See the file album4.jpg to see the title of album #4
See the file album5.jpg to see the title of album #5
See the file album6.jpg to see the title of album #6
See the file album7.jpg to see the title of album #7
See the file album8.jpg to see the title of album #8

All album titles (the text of the <listitem> elements) are converted to JPEG graphics. In this example, the file album8.jpg looks like Figure C-3.

Figure C-3

Figure C-3. Generated graphic for the eighth <listitem> element

If we delete the file JPEGWriter.class (if the .class file is missing, the function isn't available), we get these results instead:


1. A Love Supreme
2. Beat Crazy
3. Here Come the Warm Jets
4. Kind of Blue
5. London Calling
6. Remain in Light
7. The Joshua Tree
8. The Indestructible Beat of Soweto
generate-id() FunctionGenerates a unique ID (an XML name) for a given node. If no node-set is given, generate-id() generates an ID for the context node.

Synopsis

string generate-id(node-set?)

Inputs

An optional node-set. If no node-set is given, this function generates an ID for the context node. If the node-set is empty, generate-id() returns an empty string.

Output

A unique ID, or an empty string if an empty node-set is given. Several things about the generate-id() function are important to know:

  • For a given transformation, every time you invoke generate-id() against a given node, the XSLT processor must return the same ID. The ID can't change while you're doing a transformation. If you ask the XSLT processor to transform your document with this stylesheet tomorrow, there's no guarantee that generate-id() will generate the same ID the second time around. All of tomorrow's calls to generate-id() will generate the same ID, but that ID might not be the one generated today.

  • The generate-id() function is not required to check if its generated ID duplicates an ID that's already in the document. In other words, if an element in your document has an attribute of type ID with the value sdk3829a, there's a remote possibility that an ID returned by generate-id() would have the value sdk3829a. It's not likely, but it could happen.

  • If you invoke generate-id() against two different nodes, the two generated IDs must be different.

  • Given a node-set, generate-id() returns an ID for the node in the node-set that occurs first in document order.

  • If the node-set you pass to the function is empty (you invoke generate-id(fleeber), but there are no <fleeber> elements in the current context), generate-id() returns an empty string.

Defined in

XSLT section 12.4, Miscellaneous Additional Functions.

Example

Here's a simple stylesheet that uses the document('') function to access all of its own <xsl:text> nodes. It then uses generate-id() to generate a unique ID for each of those nodes, then calls generate-id() again to illustrate that the function generates the same ID for a given node. Here's the stylesheet:

<?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>A test of the generate-id() function:</xsl:text>

    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:for-each select="document('')//xsl:text">
      <xsl:text>Node name: </xsl:text>
      <xsl:value-of select="name()"/>
      <xsl:text> - generated id: </xsl:text>
      <xsl:value-of select="generate-id()"/>
      <xsl:value-of select="$newline"/>
    </xsl:for-each>
    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>Now we'll try it again...</xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:for-each select="document('')//xsl:text">
      <xsl:text>Node name: </xsl:text>
      <xsl:value-of select="name()"/>
      <xsl:text> - generated id: </xsl:text>
      <xsl:value-of select="generate-id()"/>
      <xsl:value-of select="$newline"/>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

Our stylesheet generates these results:


A test of the generate-id() function:

Node name: xsl:text - generated id: NC
Node name: xsl:text - generated id: N16
Node name: xsl:text - generated id: N22
Node name: xsl:text - generated id: N28
Node name: xsl:text - generated id: N38
Node name: xsl:text - generated id: N44
Node name: xsl:text - generated id: N4A


Now we'll try it again...

Node name: xsl:text - generated id: NC
Node name: xsl:text - generated id: N16
Node name: xsl:text - generated id: N22
Node name: xsl:text - generated id: N28
Node name: xsl:text - generated id: N38
Node name: xsl:text - generated id: N44
Node name: xsl:text - generated id: N4A

The IDs generated each time are the same.

id() FunctionReturns the node in the source tree whose ID attribute matches the value passed in as input.

Synopsis

node-set id(object)

Inputs

An object. If the input object is a node-set, the result is a node-set that contains the result of applying the id() function to the string value of each node in the argument node-set. Usually, the argument is some other node type, which is (or is converted to) a string. That string is then used as the search value while all attributes of type ID are searched.

Remember that a limitation of the XML ID datatype is that a single set of names across all attributes is declared to be of type ID. The XSLT key() function and the associated <xsl:key> element address this and other limitations; see the key() function and <xsl:key> for more information.

Output

A node-set containing all nodes whose attributes of type ID match the string values of the input node-set. In practice, this node-set is a single node, the node whose attribute of type ID matches a string value.

Defined in

XPath section 4.1, Node Set Functions.

Example

For our example, we'll take this shortened version of the glossary we discussed earlier:

<?xml version="1.0" ?>
<!DOCTYPE glossary SYSTEM "glossary.dtd">
<glossary>
  <glentry>
    <term id="applet">applet</term>
    <defn>
      An application program,
      written in the Java programming language, that can be 
      retrieved from a web server and executed by a web browser. 
      A reference to an applet appears in the markup for a web 
      page, in the same way that a reference to a graphics
      file appears; a browser retrieves an applet in the same 
      way that it retrieves a graphics file. 
      For security reasons, an applet's access rights are limited
      in two ways: the applet cannot access the filesystem of the 
      client upon which it is executing, and the applet's 
      communication across the network is limited to the server 
      from which it was downloaded. 
      Contrast with <xref refid="servlet"/>.
    </defn>
  </glentry>

  <glentry>
    <term id="servlet">servlet</term>
    <defn>
      An application program, written in the Java programming language, 
      that is executed on a web server. A reference to a servlet 
      appears in the markup for a web page, in the same way that a 
      reference to a graphics file appears. The web server executes
      the servlet and sends the results of the execution (if there are
      any) to the web browser. Contrast with <xref refid="applet" />.
    </defn>
  </glentry>
</glossary>

Here's the stylesheet we'll use to resolve the references:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:strip-space elements="*"/>

  <xsl:template match="/">
    <xsl:apply-templates select="glossary"/>
  </xsl:template>

  <xsl:template match="glossary">
    <html>
      <head>
        <title>
          <xsl:text>Glossary Listing </xsl:text>
        </title>
      </head>
      <body>
        <h1>
          <xsl:text>Glossary Listing </xsl:text>
        </h1>
        <xsl:apply-templates select="glentry"/>
      </body>
    </html>
  </xsl:template>

  <xsl:template match="glentry">
    <p>
      <b>
        <a>
          <xsl:attribute name="name">
            <xsl:value-of select="term/@id" />
          </xsl:attribute>
        </a>

        <xsl:value-of select="term"/>
        <xsl:text>: </xsl:text>
      </b>
      <xsl:apply-templates select="defn"/>
    </p>
  </xsl:template>

  <xsl:template match="defn">
    <xsl:apply-templates 
     select="*|comment()|processing-instruction()|text()"/>
  </xsl:template>

  <xsl:template match="xref">
    <a>
      <xsl:attribute name="href">
        <xsl:text>#</xsl:text><xsl:value-of select="@refid"/>
      </xsl:attribute>
      <xsl:choose>
        <xsl:when test="id(@refid)/@xreftext">
          <xsl:value-of select="id(@refid)/@xreftext"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="id(@refid)"/>
        </xsl:otherwise>
      </xsl:choose>
    </a>
  </xsl:template>

</xsl:stylesheet>

Our stylesheet generates these results:

<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Glossary Listing </title>
</head>
<body>
<h1>Glossary Listing </h1>
<p>
<b><a name="applet"></a>applet: </b>
      An application program,
      written in the Java programming language, that can be 
      retrieved from a web server and executed by a web browser. 
      A reference to an applet appears in the markup for a web 
      page, in the same way that a reference to a graphics
      file appears; a browser retrieves an applet in the same 
      way that it retrieves a graphics file. 
      
      For security reasons, an applet's access rights are limited
      in two ways: the applet cannot access the filesystem of the 
      client upon which it is executing, and the applet's 
      communication across the network is limited to the server 
      from which it was downloaded. 
      Contrast with <a href="#servlet">servlet</a>.
    </p>
<p>
<b><a name="servlet"></a>servlet: </b>
      An application program, written in the Java programming language, 
      that is executed on a web server. A reference to a servlet 
      appears in the markup for a web page, in the same way that a 
      reference to a graphics file appears. The web server executes
      the servlet and sends the results of the execution (if there are
      any) to the web browser. Contrast with <a href="#applet">applet</a>.
    </p>
</body>
</html>

When rendered in a browser, our hyperlinked document looks like Figure C-4.

Figure C-4

Figure C-4. Generated HTML glossary

key() FunctionReferences a relation defined with an <xsl:key> element. Conceptually, the key() function works similarly to the id() function, although keys are more flexible than IDs.

Synopsis

node-set key(stringobject)

Inputs

The name of the key (defined by an <xsl:key> element) and an object. If the object is a node-set, then the key() function applies itself to the string value of each node in the node-set and returns the node-set of the result of all those key() function invocations. If the object is any other type, it is converted to a string as if by a call to the string() function.

Output

A node-set containing the nodes in the same document as the context node whose values for the requested key match the search argument(s). In other words, if our stylesheet has an <xsl:key> element that defines a key named postalcodes based on the <postalcode> child of all <address> elements in the current document, the function call key(postalcodes, '34829') returns a node-set containing all the <address> elements with a <postalcode> element whose value is 34829.

Defined in

XSLT section 12.2, Keys.

Example

To illustrate the power of the key() function, we'll use this document -- a truncated version of the glossary we discussed in Chapter 5, "Creating Links and Cross-References":

<?xml version="1.0" ?>
<glossary>
  <glentry>
    <term id="applet">applet</term>
    <defn topic="Java" language="en">
      An application program,
      written in the Java programming language, that can be 
      retrieved from a web server and executed by a web browser. 
      A reference to an applet appears in the markup for a web 
      page, in the same way that a reference to a graphics
      file appears; a browser retrieves an applet in the same 
      way that it retrieves a graphics file. 
      For security reasons, an applet's access rights are limited
      in two ways: the applet cannot access the filesystem of the 
      client upon which it is executing, and the applet's 
      communication across the network is limited to the server 
      from which it was downloaded. 
      Contrast with <xref refid="servlet"/>.
    </defn>

    <defn topic="Java" language="it">
      [Pretend this is an Italian definition of applet.]
    </defn>
    <defn topic="Java" language="es">
      [Pretend this is a Spanish definition of applet.]
    </defn>
  </glentry>

  <glentry>
    <term id="DMZlong" xreftext="demilitarized zone">demilitarized 
      zone (DMZ)</term>
    <defn topic="security" language="en">
      In network security, a network that is isolated from, and 
      serves as a neutral zone between, a trusted network (for example, 
      a private intranet) and an untrusted network (for example, the
      Internet). One or more secure gateways usually control access 
      to the DMZ from the trusted or the untrusted network.
    </defn>
    <defn topic="security" language="it">
      [Pretend this is an Italian definition of DMZ.]
    </defn>
    <defn topic="security" language="es">
      [Pretend this is a Spanish definition of DMZ.]
    </defn>
    <defn topic="security" language="jp">
      [Pretend this is a Japanese definition of DMZ.]
    </defn>
    <defn topic="security" language="de">
      [Pretend this is a German definition of DMZ.]
    </defn>
  </glentry>

  <glentry>
    <term id="servlet">servlet</term>
    <defn topic="Java" language="en">
      An application program, written in the Java programming language, 
      that is executed on a web server. A reference to a servlet 
      appears in the markup for a web page, in the same way that a 
      reference to a graphics file appears. The web server executes
      the servlet and sends the results of the execution (if there are
      any) to the web browser. Contrast with <xref refid="applet" />.
    </defn>
    <defn topic="Java" language="es">
      [Pretend this is a Spanish definition of servlet.]
    </defn>
    <defn topic="Java" language="it">
      [Pretend this is an Italian definition of servlet.]
    </defn>

    <defn topic="Java" language="de">
      [Pretend this is a German definition of servlet.]
    </defn>
    <defn topic="Java" language="jp">
      [Pretend this is a Japanese definition of servlet.]
    </defn>
  </glentry>
</glossary>

Here's the stylesheet we'll use to process this document. Notice that we define two <xsl:key> elements to index the XML document in two different ways:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:strip-space elements="*"/>

  <xsl:key name="language-index" match="defn" use="@language"/>
  <xsl:key name="term-ids"       match="term" use="@id"/>

  <xsl:param name="targetLanguage"/>

  <xsl:template match="/">
    <xsl:apply-templates select="glossary"/>
  </xsl:template>

  <xsl:template match="glossary">
    <html>
      <head>
        <title>
          <xsl:text>Glossary Listing: </xsl:text>
        </title>
      </head>
      <body>
        <h1>
          <xsl:text>Glossary Listing: </xsl:text>
        </h1>
        <xsl:for-each select="key('language-index', $targetLanguage)">
          <xsl:apply-templates select="ancestor::glentry"/>
        </xsl:for-each>
      </body>
    </html>
  </xsl:template>

  <xsl:template match="glentry">
    <p>
      <b>
        <a>
          <xsl:attribute name="name">
            <xsl:value-of select="term/@id" />
          </xsl:attribute>
        </a>
        <xsl:value-of select="term"/>
        <xsl:text>: </xsl:text>
      </b>
      <xsl:apply-templates select="defn[@language=$targetLanguage]"/>
    </p>
  </xsl:template>

  <xsl:template match="defn">
    <xsl:apply-templates 
     select="*|comment()|processing-instruction()|text()"/>
  </xsl:template>

  <xsl:template match="xref">
    <a>
      <xsl:attribute name="href">
        <xsl:text>#</xsl:text><xsl:value-of select="@refid"/>
      </xsl:attribute>
      <xsl:choose>
        <xsl:when test="key('term-ids', @refid)[1]/@xreftext">
          <xsl:value-of select="key('term-ids', @refid)[1]/@xreftext"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="key('term-ids', @refid)[1]"/>
        </xsl:otherwise>
      </xsl:choose>
    </a>
  </xsl:template>

</xsl:stylesheet>

Transforming the glossary with a targetLanguage of en gives these results:

<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Glossary Listing: </title>
</head>
<body>
<h1>Glossary Listing: </h1>
<p>
<b><a name="applet"></a>applet: </b>
      An application program,
      written in the Java programming language, that can be 
      retrieved from a web server and executed by a web browser. 
      A reference to an applet appears in the markup for a web 
      page, in the same way that a reference to a graphics
      file appears; a browser retrieves an applet in the same 
      way that it retrieves a graphics file. 
      For security reasons, an applet's access rights are limited
      in two ways: the applet cannot access the filesystem of the 
      client upon which it is executing, and the applet's 
      communication across the network is limited to the server 
      from which it was downloaded. 
      Contrast with <a href="#servlet">servlet</a>.
    </p>
<p>
<b><a name="DMZlong"></a>demilitarized 
      zone (DMZ): </b>
      In network security, a network that is isolated from, and 
      serves as a neutral zone between, a trusted network (for example, 
      a private intranet) and an untrusted network (for example, the
      Internet). One or more secure gateways usually control access 
      to the DMZ from the trusted or the untrusted network.
    </p>
<p>
<b><a name="servlet"></a>servlet: </b>
      An application program, written in the Java programming language, 
      that is executed on a web server. A reference to a servlet 
      appears in the markup for a web page, in the same way that a 
      reference to a graphics file appears. The web server executes
      the servlet and sends the results of the execution (if there are
      any) to the web browser. Contrast with <a href="#applet">applet</a>.
    </p>
</body>
</html>

Figure C-5 shows how this document looks when it's rendered in a browser. Using a targetLanguage of jp gives us these results instead:

Figure C-5

Figure C-5. Generated HTML glossary

<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Glossary Listing: </title>
</head>
<body>
<h1>Glossary Listing: </h1>
<p>
<b><a name="DMZlong"></a>demilitarized 
      zone (DMZ): </b>
      [Pretend this is a Japanese definition of DMZ.]
    </p>
<p>
<b><a name="servlet"></a>servlet: </b>
      [Pretend this is a Japanese definition of servlet.]
    </p>
</body>
</html>
      </programlisting>

When rendered, the document looks like Figure C-6. Notice that we get entirely different results when we change the targetLanguage.

Figure C-6

Figure C-6. Generated HTML glossary

lang() FunctionDetermines whether a given language string is the same as, or is a sublanguage of, the language of the context node, as defined by an xml:lang attribute.

Synopsis

boolean lang(string)

Inputs

A string representing a language code. If the context node has a language of xml:lang="en-us", invoking the lang() function with any of the values en, EN, and en-us returns the boolean value true, while invoking lang() with the value en-gb returns the boolean value false.

Output

If the argument string is the same as, or is a sublanguage of, the context node's language, lang() returns the boolean value true. If the context node does not have an xml:lang attribute, then the value of the xml:lang attribute of its nearest ancestor is used instead. If there is no such attribute, then the lang() function returns the boolean value false. When comparing the language code of the context node with the argument string, the lang() function ignores case.

Defined in

XPath section 4.3, Boolean Functions.

Example

Here is an XML document that uses language codes:

<?xml version="1.0"?>
<list xml:lang="en">
  <title>Albums I've bought recently:</title>
  <listitem>The Sacred Art of Dub</listitem>
  <listitem>Only the Poor Man Feel It</listitem>
  <listitem>Excitable Boy</listitem>
  <listitem xml:lang="sw">Aki Special</listitem>
  <listitem xml:lang="en-gb">Combat Rock</listitem>
  <listitem xml:lang="zu">Talking Timbuktu</listitem>
  <listitem xml:lang="jz">The Birth of the Cool</listitem>
</list>

Here's a stylesheet that uses the lang() function:

<?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:for-each select="list/listitem">
      <xsl:choose>
        <xsl:when test="lang('EN')">
          <xsl:text>Here's an English-language album: </xsl:text>
        </xsl:when>
        <xsl:otherwise>
          <xsl:text>-------> Here's some World music: </xsl:text>
        </xsl:otherwise>
      </xsl:choose>
      <xsl:value-of select="."/>
      <xsl:value-of select="$newline"/>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

Finally, here are the results:


Here's an English-language album: The Sacred Art of Dub
Here's an English-language album: Only the Poor Man Feel It
Here's an English-language album: Excitable Boy
-------> Here's some World music: Aki Special
Here's an English-language album: Combat Rock
-------> Here's some World music: Talking Timbuktu
-------> Here's some World music: The Birth of the Cool
last() FunctionReturns the position of the last node in the current context. This function is useful for defining templates for the last occurrence of a given element or for testing if a given node is the last in the node-set to which it belongs.

Synopsis

number last()

Inputs

None.

Output

A number equal to the number of nodes in the current context. For example, if the current context contains 12 <li> nodes, last() returns 12.

Defined in

XPath section 4.1, Node Set Functions.

Example

We'll use the last() function to handle the last item in a list in a special way. Here's the XML document we'll use:

<?xml version="1.0"?>
<list>
  <title>A few of my favorite albums</title>
  <listitem>A Love Supreme</listitem>
  <listitem>Beat Crazy</listitem>
  <listitem>Here Come the Warm Jets</listitem>
  <listitem>Kind of Blue</listitem>
  <listitem>London Calling</listitem>
  <listitem>Remain in Light</listitem>
  <listitem>The Joshua Tree</listitem>
  <listitem>The Indestructible Beat of Soweto</listitem>
</list>

Here is the stylesheet that handles the last <listitem> in the list differently:

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

  <xsl:output method="html"/>

  <xsl:template match="/">
    <html>
      <head>
        <title>
          <xsl:value-of select="/list/title"/>
        </title>
      </head>
      <body>
        <h1>
          <xsl:value-of select="/list/title"/>
        </h1>
        <ul>
          <xsl:for-each select="/list/listitem">
            <xsl:choose>
              <xsl:when test="position()=last()">
                <li><b>Last, but not least: </b><xsl:value-of select="."/></li>
              </xsl:when>
              <xsl:otherwise>
                <li><xsl:value-of select="."/></li>
              </xsl:otherwise>
            </xsl:choose>
          </xsl:for-each>
        </ul>
      </body>
    </html>
  </xsl:template>

</xsl:stylesheet>

When we transform the XML document with this stylesheet, here are the results:

<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>A few of my favorite albums</title>
</head>
<body>
<h1>A few of my favorite albums</h1>
<ul>
<li>A Love Supreme</li>
<li>Beat Crazy</li>
<li>Here Come the Warm Jets</li>
<li>Kind of Blue</li>
<li>London Calling</li>
<li>Remain in Light</li>
<li>The Joshua Tree</li>
<li>
<b>Last, but not least: </b>The Indestructible Beat of Soweto</li>
</ul>
</body>
</html>

When rendered, the HTML file looks like Figure C-7.

Figure C-7

Figure C-7. Generated HTML document

local-name() FunctionReturns the local part of the first node in the argument node-set.

Synopsis

string local-name(node-set?)

Inputs

A node-set. If the node-set is empty, the function returns an empty string. If the node-set is omitted, the function uses a node-set with the context node as its only member.

Output

A string corresponding to the local name of the first element in the argument node-set. If the node-set is empty, the local-name() function returns an empty string.

Defined in

XPath section 4.1, Node Set Functions.

Example

Here is a stylesheet that uses the document() function to process all its own nodes. It then calls the local-name() function against each node.

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:months="Lookup table for month names">

  <months:name sequence="12">December</months:name>
  <months:name sequence="01">January</months:name>
  <months:name sequence="02">February</months:name>
  <months:name sequence="03">March</months:name>
  <months:name sequence="04">April</months:name>
  <months:name sequence="05">May</months:name>
  <months:name sequence="06">June</months:name>
  <months:name sequence="07">July</months:name>
  <months:name sequence="08">August</months:name>
  <months:name sequence="09">September</months:name>
  <months:name sequence="10">October</months:name>
  <months:name sequence="11">November</months:name>

  <xsl:output method="text"/>

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

  <xsl:template match="/">
    <xsl:value-of select="$newline"/>
    <xsl:text>A test of the local-name() function:</xsl:text>

    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:for-each select="document('')//*">
      <xsl:text>local-name: </xsl:text>
      <xsl:value-of select="local-name()"/>
      <xsl:value-of select="$newline"/>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

The stylesheet generates these results:


A test of the local-name() function:

local-name: stylesheet
local-name: name
local-name: name
local-name: name
local-name: name
local-name: name
local-name: name
local-name: name
local-name: name
local-name: name
local-name: name
local-name: name
local-name: name
local-name: output
local-name: variable
local-name: text
local-name: template
local-name: value-of
local-name: text
local-name: value-of
local-name: value-of
local-name: for-each
local-name: text
local-name: value-of
local-name: value-of
name() FunctionReturns the qualified name of a node. The qualified name includes the appropriate namespace prefix. For information on the namespace URI (not the prefix), XPath provides the namespace-uri() function.

Synopsis

string name(node-set?)

Inputs

An optional node-set. If no node-set is given, the name() function creates a node-set with the context node as its only member.

Output

The expanded name of the node. If the argument node-set is empty, or if the first node in the node-set does not have an expanded name, an empty string is returned.

Defined in

XPath section 4.1, Node Set Functions.

Example

Here is the XML document we'll use to demonstrate the name() function:

<?xml version="1.0"?>
<report>
  <title>Miles Flown in 2001</title>
  <month sequence="01">
    <miles-flown>12379</miles-flown>
    <miles-earned>35215</miles-earned>
  </month>
  <month sequence="02">
    <miles-flown>32857</miles-flown>
    <miles-earned>92731</miles-earned>
  </month>
  <month sequence="03">
    <miles-flown>19920</miles-flown>
    <miles-earned>76725</miles-earned>
  </month>
  <month sequence="04">
    <miles-flown>18903</miles-flown>
    <miles-earned>31781</miles-earned>
  </month>
</report>

We'll use this stylesheet to output the value of the name() function for each node in the XML document:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:months="Lookup table for month names">

  <months:name sequence="12">December</months:name>
  <months:name sequence="01">January</months:name>
  <months:name sequence="02">February</months:name>
  <months:name sequence="03">March</months:name>
  <months:name sequence="04">April</months:name>
  <months:name sequence="05">May</months:name>
  <months:name sequence="06">June</months:name>
  <months:name sequence="07">July</months:name>
  <months:name sequence="08">August</months:name>
  <months:name sequence="09">September</months:name>
  <months:name sequence="10">October</months:name>
  <months:name sequence="11">November</months:name>

  <xsl:output method="text"/>

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

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

    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:for-each select="document('')//*">
      <xsl:text>name: </xsl:text>
      <xsl:value-of select="name()"/>
      <xsl:value-of select="$newline"/>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

When we transform the XML document with this stylesheet, here are the results:


A test of the name() function:

name: xsl:stylesheet
name: months:name
name: months:name
name: months:name
name: months:name
name: months:name
name: months:name
name: months:name
name: months:name
name: months:name
name: months:name
name: months:name
name: months:name
name: xsl:output
name: xsl:variable
name: xsl:text
name: xsl:template
name: xsl:value-of
name: xsl:text
name: xsl:value-of
name: xsl:value-of
name: xsl:for-each
name: xsl:text
name: xsl:value-of
name: xsl:value-of
namespace-uri() FunctionReturns the namespace URI of the first node in the argument node-set.

Synopsis

string namespace-uri(node-set?)

Inputs

A node-set. If the node-set is omitted, the namespace-uri() function creates a node-set that has the context node as its only member.

Output

The namespace URI of the first node in the argument node-set. If the argument node-set is empty, the first node has no namespace URI, or the first node has a namespace URI that is null, an empty string is returned. Be aware that the namespace-uri() function returns an empty string for all nodes other than element and attribute nodes.

Defined in

XPath section 4.1, Node Set Functions.

Example

Here is a stylesheet that uses the document() function to examine its own nodes and then invoke the namespace-uri() against each of them:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:months="Lookup table for month names">

  <months:name sequence="01">January</months:name>
  <months:name sequence="02">February</months:name>
  <months:name sequence="03">March</months:name>
  <months:name sequence="04">April</months:name>
  <months:name sequence="05">May</months:name>
  <months:name sequence="06">June</months:name>
  <months:name sequence="07">July</months:name>
  <months:name sequence="08">August</months:name>
  <months:name sequence="09">September</months:name>
  <months:name sequence="10">October</months:name>
  <months:name sequence="11">November</months:name>
  <months:name sequence="12">December</months:name>

  <xsl:output method="text"/>

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

  <xsl:template match="/">
    <xsl:value-of select="$newline"/>
    <xsl:text>A test of the namespace-uri() function:</xsl:text>

    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:for-each select="document('')//*">
      <xsl:text>namespace URI: </xsl:text>
      <xsl:value-of select="namespace-uri()"/>
      <xsl:value-of select="$newline"/>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

Here are the results of our stylesheet:


A test of the namespace-uri() function:

namespace URI: http://www.w3.org/1999/XSL/Transform
namespace URI: Lookup table for month names
namespace URI: Lookup table for month names
namespace URI: Lookup table for month names
namespace URI: Lookup table for month names
namespace URI: Lookup table for month names
namespace URI: Lookup table for month names
namespace URI: Lookup table for month names
namespace URI: Lookup table for month names
namespace URI: Lookup table for month names
namespace URI: Lookup table for month names
namespace URI: Lookup table for month names
namespace URI: Lookup table for month names
namespace URI: http://www.w3.org/1999/XSL/Transform
namespace URI: http://www.w3.org/1999/XSL/Transform
namespace URI: http://www.w3.org/1999/XSL/Transform
namespace URI: http://www.w3.org/1999/XSL/Transform
namespace URI: http://www.w3.org/1999/XSL/Transform
namespace URI: http://www.w3.org/1999/XSL/Transform
namespace URI: http://www.w3.org/1999/XSL/Transform
namespace URI: http://www.w3.org/1999/XSL/Transform
namespace URI: http://www.w3.org/1999/XSL/Transform
namespace URI: http://www.w3.org/1999/XSL/Transform
namespace URI: http://www.w3.org/1999/XSL/Transform
namespace URI: http://www.w3.org/1999/XSL/Transform
normalize-space() FunctionRemoves extra whitespace from its argument string.

Synopsis

string normalize-space(string?)

Inputs

An optional string. If the argument is omitted, the normalize-space() function uses the string value of the context node.

Output

The argument string, with whitespace removed as follows:

  • All leading whitespace is removed.

  • All trailing whitespace is removed.

  • Within the string, any sequence of whitespace characters is replaced with a single space.

Defined in

XPath section 4.2, String Functions.

Example

Here is a short example that demonstrates how normalize-space() works:

<?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:variable name="testString">
    <xsl:text>                 This
is


a string
with lots of


whitespace.

</xsl:text>
    </xsl:variable>

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

    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   normalize-space('       Hello,            World!')="</xsl:text>
    <xsl:value-of select="normalize-space('       Hello,            World!')"/>
    <xsl:text>"</xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:text>   normalize-space($newline)="</xsl:text>
    <xsl:value-of select="normalize-space($newline)"/>
    <xsl:text>"</xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:text>   normalize-space($testString)="</xsl:text>
    <xsl:value-of select="normalize-space($testString)"/>
    <xsl:text>"</xsl:text>
    <xsl:value-of select="$newline"/>
  </xsl:template>

</xsl:stylesheet>

The stylesheet generates this output:


Tests of the normalize-space() function:

   normalize-space('       Hello,            World!')="Hello, World!"
   normalize-space($newline)=""
   normalize-space($testString)="This is a string with lots of whitespace."
not() FunctionReturns the negation of its argument. If the argument is not a boolean value already, it is converted to a boolean value using the rules described in the boolean() function entry.

Synopsis

boolean not(boolean)

Inputs

A boolean value, or more commonly, an XPath expression that evaluates to a boolean value.

Output

false if the input parameter is true; true if the input parameter is false.

Defined in

XPath section 4.3, Boolean Functions.

Example

To demonstrate the not() function, we'll use the same stylesheet and XML document we used for the boolean() function. Here's our XML document:

<?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>Yes!  The Eiffel Tower was the world's 
tallest building until 1932, when
New York's Empire State Building opened. </true>
<false>No, the Eiffel Tower was the world's 
tallest building for over 30 years.</false>
</question>
</test>

We'll process this document with the following stylesheet, which uses the not() to negate all boolean() function calls:

<?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 not() function:</xsl:text>

    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:choose>
      <xsl:when test="not(boolean(true()))">
        <xsl:text>   "not(boolean(true()))"   returned true!</xsl:text>
      </xsl:when>
      <xsl:otherwise>
        <xsl:text>   "not(boolean(true()))"   returned false!</xsl:text>
      </xsl:otherwise>
    </xsl:choose>

    <xsl:value-of select="$newline"/>
    <xsl:choose>
      <xsl:when test="not(boolean(true))">
        <xsl:text>   "not(boolean(true))"     returned true!</xsl:text>
      </xsl:when>
      <xsl:otherwise>
        <xsl:text>   "not(boolean(true))"     returned false!</xsl:text>
      </xsl:otherwise>
    </xsl:choose>

    <xsl:value-of select="$newline"/>
    <xsl:choose>
      <xsl:when test="not(boolean('false'))">
        <xsl:text>   "not(boolean('false'))"  returned true!</xsl:text>
      </xsl:when>
      <xsl:otherwise>
        <xsl:text>   "not(boolean('false'))"  returned false!</xsl:text>
      </xsl:otherwise>
    </xsl:choose>

    <xsl:value-of select="$newline"/>
    <xsl:choose>
      <xsl:when test="not(boolean('7'))">
        <xsl:text>   "not(boolean('7'))"      returned true!</xsl:text>
      </xsl:when>
      <xsl:otherwise>
        <xsl:text>   "not(boolean('7'))"      returned false!</xsl:text>
      </xsl:otherwise>
    </xsl:choose>

    <xsl:value-of select="$newline"/>
    <xsl:choose>
      <xsl:when test="not(boolean(/true))">
        <xsl:text>   "not(boolean(/true))"    returned true!</xsl:text>
      </xsl:when>
      <xsl:otherwise>
        <xsl:text>   "not(boolean(/true))"    returned false!</xsl:text>
      </xsl:otherwise>
    </xsl:choose>

    <xsl:value-of select="$newline"/>
    <xsl:choose>
      <xsl:when test="not(boolean(//true))">
        <xsl:text>   "not(boolean(//true))"   returned true!</xsl:text>
      </xsl:when>
      <xsl:otherwise>
        <xsl:text>   "not(boolean(//true))"   returned false!</xsl:text>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

Here are the results:


Tests of the not() function:

   "not(boolean(true()))"   returned false!
   "not(boolean(true))"     returned true!
   "not(boolean('false'))"  returned false!
   "not(boolean('7'))"      returned false!
   "not(boolean(/true))"    returned true!
   "not(boolean(//true))"   returned false!

As you'd expect, these results are the exact opposite of the results we got when we tested the boolean() function.

number() FunctionConverts its argument to a number.

Synopsis

number number(object?)

Inputs

An object. The object is converted to a number as described in the following subsection.

Output

A number. The object is converted to a number as follows:

  • If the argument is a boolean value, the value true is converted to the number 1; the value false is converted to the number 0.

  • If the argument is a node-set, the node-set is converted to a string as if it were passed to the string() function, then that string is converted to a number like any other string. (Remember that the string() function returns the string value of the first node in the node-set.)

  • If the argument is a string, it is converted as follows:

    • If the string consists of optional whitespace, followed by an optional minus sign (-), followed by a number, followed by whitespace, it is converted to the floating-point value nearest to the mathematical value represented by the string. (The IEEE 754 standard defines a round-to-nearest rule; see the standard for more information.)

    • Any other string is converted to the value NaN (not a number).

  • If the argument is any other type, it is converted to a number in a way that depends on that type. See the documentation for your XSLT processor to find out what other types are supported and how they are converted to numbers.

Defined in

XPath section 4.4, Number Functions.

Example

Here is the XML document we'll use to test the number() function:

<?xml version="1.0"?>
<report>
  <title>Miles Flown in 2001</title>
  <month sequence="01">
    <miles-flown>12379</miles-flown>
    <miles-earned>35215</miles-earned>
  </month>
  <month sequence="02">
    <miles-flown>32857</miles-flown>
    <miles-earned>92731</miles-earned>
  </month>
  <month sequence="03">
    <miles-flown>19920</miles-flown>
    <miles-earned>76725</miles-earned>
  </month>
  <month sequence="04">
    <miles-flown>18903</miles-flown>
    <miles-earned>31781</miles-earned>
  </month>
</report>

We'll test the number() function with a variety of arguments:

<?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 number() function:</xsl:text>

    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   number(true())=</xsl:text>
    <xsl:value-of select="number(true())"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   number(false())=</xsl:text>
    <xsl:value-of select="number(false())"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   number(/report/month[2]/miles-flown)=</xsl:text>
    <xsl:value-of select="number(/report/month[2]/miles-flown)"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   number(//miles-flown)=</xsl:text>
    <xsl:value-of select="number(//miles-flown)"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   number(/report/title)=</xsl:text>
    <xsl:value-of select="number(/report/title)"/>
  </xsl:template>

</xsl:stylesheet>

The output of our stylesheet looks like this:


Tests of the number() function:

   number(true())=1
   number(false())=0
   number(/report/month[2]/miles-flown)=32857
   number(//miles-flown)=12379
   number(/report/title)=NaN
position() FunctionReturns a number equal to the context position from the current context.

Synopsis

number position()

Inputs

None.

Output

A number equal to the position of the current node in the evaluation context.

Defined in

XPath section 4.1, Node Set Functions.

Examples

This example uses the position() function to determine the background color of the rows of a table. The background colors cycle through the options white, darkgray, and lightgreen. Here's the XML document we'll use:

<?xml version="1.0"?>
<list>
  <title>A few of my favorite albums</title>
  <listitem>A Love Supreme</listitem>
  <listitem>Beat Crazy</listitem>
  <listitem>Here Come the Warm Jets</listitem>
  <listitem>Kind of Blue</listitem>
  <listitem>London Calling</listitem>
  <listitem>Remain in Light</listitem>
  <listitem>The Joshua Tree</listitem>
  <listitem>The Indestructible Beat of Soweto</listitem>
</list>

We'll use this stylesheet to generate our HTML document:

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

  <xsl:output method="html"/>

  <xsl:template match="/">
    <html>
      <head>
        <title>
          <xsl:value-of select="/list/title"/>
        </title>
      </head>
      <body>
        <h1>
          <xsl:value-of select="/list/title"/>
        </h1>
        <table border="1">
          <xsl:for-each select="/list/listitem">
            <xsl:variable name="background-color">
              <xsl:choose>
                <xsl:when test="position() mod 3 = 1">white</xsl:when>
                <xsl:when test="position() mod 3 = 2">darkgray</xsl:when>
                <xsl:otherwise>lightgreen</xsl:otherwise>
              </xsl:choose>
            </xsl:variable>
            <tr bgcolor="{$background-color}">
              <td>
                <b><xsl:value-of select="."/></b>
              </td>
            </tr>
          </xsl:for-each>
        </table>
      </body>
    </html>
  </xsl:template>

</xsl:stylesheet>

Our stylesheet generates the following results:

<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>A few of my favorite albums</title>
</head>
<body>
<h1>A few of my favorite albums</h1>
<table border="1">
<tr bgcolor="white">
<td><b>A Love Supreme</b></td>
</tr>
<tr bgcolor="darkgray">
<td><b>Beat Crazy</b></td>
</tr>
<tr bgcolor="lightgreen">
<td><b>Here Come the Warm Jets</b></td>
</tr>
<tr bgcolor="white">
<td><b>Kind of Blue</b></td>
</tr>
<tr bgcolor="darkgray">
<td><b>London Calling</b></td>
</tr>
<tr bgcolor="lightgreen">
<td><b>Remain in Light</b></td>
</tr>
<tr bgcolor="white">
<td><b>The Joshua Tree</b></td>
</tr>
<tr bgcolor="darkgray">
<td><b>The Indestructible Beat of Soweto</b></td>
</tr>
</table>
</body>
</html>

When rendered, the HTML file looks like Figure C-8.

Figure C-8

Figure C-8. HTML file displaying items with different background colors

round() FunctionReturns the integer closest to the argument.

Synopsis

number round(number)

Description

If two numbers are equally close to the argument (1 and 2 are equally close to 1.5), the number closest to positive infinity is returned. Various argument values are handled as follows:

  • If the argument is NaN (not a number), the round() function returns NaN.

  • If the argument is positive infinity, then positive infinity is returned.

  • If the argument is negative infinity, then negative infinity is returned.

  • If the argument is positive zero, then positive zero is returned.

  • If the argument is negative zero, then negative zero is returned.

  • If the argument is between zero and -0.5, then negative zero is returned.

Inputs

A number. If the argument is not a number, it is converted to a number as if it were passed to the number() function.

Output

The integer that is closest to the argument. Special cases are handled as described in this section.

Defined in

XPath section 4.4, Number Functions.

Example

The following stylesheet shows the results of invoking the round() function against a variety of values. We'll use this XML document as input:

<?xml version="1.0"?>
<report>
  <title>Miles Flown in 2001</title>
  <month sequence="01">
    <miles-flown>12379</miles-flown>
    <miles-earned>35215</miles-earned>
  </month>
  <month sequence="02">
    <miles-flown>32857</miles-flown>
    <miles-earned>92731</miles-earned>
  </month>
  <month sequence="03">
    <miles-flown>19920</miles-flown>
    <miles-earned>76725</miles-earned>
  </month>
  <month sequence="04">
    <miles-flown>18903</miles-flown>
    <miles-earned>31781</miles-earned>
  </month>
</report>

Here's the stylesheet that uses the round() function:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:months="Lookup table for month names">

  <months:name sequence="01">January</months:name>
  <months:name sequence="02">February</months:name>
  <months:name sequence="03">March</months:name>
  <months:name sequence="04">April</months:name>
  <months:name sequence="05">May</months:name>
  <months:name sequence="06">June</months:name>
  <months:name sequence="07">July</months:name>
  <months:name sequence="08">August</months:name>
  <months:name sequence="09">September</months:name>
  <months:name sequence="10">October</months:name>
  <months:name sequence="11">November</months:name>
  <months:name sequence="12">December</months:name>

  <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 round() function:</xsl:text>

    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   "round('7.983')" = </xsl:text>
    <xsl:value-of select="round('7.983')"/>

    <xsl:value-of select="$newline"/>
    <xsl:text>   "round('7.5')" = </xsl:text>
    <xsl:value-of select="round('7.5')"/>

    <xsl:value-of select="$newline"/>
    <xsl:text>   "round('-7.893')" = </xsl:text>
    <xsl:value-of select="round('-7.893')"/>

    <xsl:value-of select="$newline"/>
    <xsl:text>   "round('-7.5')" = </xsl:text>
    <xsl:value-of select="round('-7.5')"/>

    <xsl:value-of select="$newline"/>
    <xsl:text>   "round(/report/month[@sequence='01']/miles-flown)" = </xsl:text>
    <xsl:value-of select="round(/report/month[@sequence='01']/miles-flown)"/>

    <xsl:value-of select="$newline"/>
    <xsl:text>   "round(document('')/*/months:name[@sequence='02'])" = </xsl:text>
    <xsl:value-of select="round(document('')/*/months:name[@sequence='02'])"/>

    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>

    <xsl:for-each select="/report/month">
      <xsl:text>   </xsl:text>
      <xsl:value-of 
        select="document('')/*/months:name[@sequence=current()/@sequence]"/>
      <xsl:text> - </xsl:text>
      <xsl:value-of select="format-number(miles-flown, '##,###')"/>
      <xsl:text> miles flown, </xsl:text>
      <xsl:value-of select="format-number(miles-earned, '##,###')"/>
      <xsl:text> miles earned.</xsl:text>
      <xsl:value-of select="$newline"/>
      <xsl:text>      (Averaged </xsl:text>
      <xsl:value-of select="round(miles-earned div miles-flown)"/>
      <xsl:text> miles earned for each mile flown.)</xsl:text>
      <xsl:value-of select="$newline"/>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

When we process our XML document with this stylesheet, the results are:


Tests of the round() function:

   "round('7.983')" = 8
   "round('7.5')" = 8
   "round('-7.893')" = -8
   "round('-7.5')" = -7
   "round(/report/month[@sequence='01']/miles-flown)" = 12379
   "round(document('')/*/months:name[@sequence='02'])" = NaN

   January - 12,379 miles flown, 35,215 miles earned.
      (Averaged 3 miles earned for each mile flown.)

   February - 32,857 miles flown, 92,731 miles earned.
      (Averaged 3 miles earned for each mile flown.)

   March - 19,920 miles flown, 76,725 miles earned.
      (Averaged 4 miles earned for each mile flown.)

   April - 18,903 miles flown, 31,781 miles earned.
      (Averaged 2 miles earned for each mile flown.)

You can compare these results to those from the ceiling() and floor() functions.

starts-with() FunctionDetermines if the first argument string begins with the second argument.

Synopsis

boolean starts-with(stringstring)

Inputs

Two strings.

Output

If the first string begins with the second, starts-with() returns the boolean value true; otherwise it returns false.

Defined in

XPath section 4.2, String Functions.

Example

We'll use this sample XML document:

<?xml version="1.0"?>
<list>
  <title>A few of my favorite albums</title>
  <listitem>A Love Supreme</listitem>
  <listitem>Beat Crazy</listitem>
  <listitem>Here Come the Warm Jets</listitem>
  <listitem>Kind of Blue</listitem>
  <listitem>London Calling</listitem>
  <listitem>Remain in Light</listitem>
  <listitem>The Joshua Tree</listitem>
  <listitem>The Indestructible Beat of Soweto</listitem>
</list>

This stylesheet outputs contents of all <listitem> elements that begin with the string "The":

<?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:for-each select="list/listitem">
      <xsl:if test="starts-with(., 'The')">
        <xsl:value-of select="position()"/>
        <xsl:text>. </xsl:text>
        <xsl:value-of select="."/>
        <xsl:value-of select="$newline"/>
      </xsl:if>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

Our stylesheet generates this result:


7. The Joshua Tree
8. The Indestructible Beat of Soweto
string() FunctionReturns the string value of the argument.

Synopsis

string string(object)

Inputs

An object. The object is converted to a string, as described in the following subsection.

Output

A string. The input argument is converted to a string as follows:

  • If the argument is a node-set, the first node in the node-set is converted to a string. (The first node in the node-set is the one that occurs first in document order.)

  • If the argument is a number, it is converted to a string as follows:

    • The value NaN is converted to the string "NaN".

    • Positive zero is converted to the string "0".

    • Negative zero is converted to the string "0".

    • Positive infinity is converted to the string "Infinity".

    • Negative infinity is converted to the string "-Infinity".

    • An integer is converted to a string representing that integer, using no decimal point and no leading zeros. If the integer is negative, it will be preceded by a minus sign (-).

    • Any other number is converted to a string with a decimal point, at least one number before the decimal point, and at least one number after the decimal point. If the number is negative, it will be preceded by a minus sign (-). There will not be any leading zeros before the decimal point (with the possible exception of the one required digit before the decimal point). After the decimal point, there will be only as many digits as needed to distinguish this number from all other numeric values defined by the IEEE 754 standard, the same standard used by the Java float and double types.

  • If the argument is a boolean value, the value true is represented by the string "true" and the value false is represented by the string "false".

  • If the argument is any other type, it is converted to a string in a way that depends on that type. See the documentation for your XSLT processor to find out what other types are supported and how they are converted to strings.

Defined in

XPath section 4.2, String Functions.

Example

Here is the XML document we'll use to test the string() function:

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

We'll test the string() function with a variety of arguments:

<?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 string() function:</xsl:text>


    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   string(count(/test))=</xsl:text>
    <xsl:value-of select="string(count(/test))"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   string(count(/test/question))=</xsl:text>
    <xsl:value-of select="string(count(/test/question))"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   string('4')=</xsl:text>
    <xsl:value-of select="string('4')"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   string(true())=</xsl:text>
    <xsl:value-of select="string(true())"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   string(false())=</xsl:text>
    <xsl:value-of select="string(false())"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   string(count(/test/question) > 5)=</xsl:text>
    <xsl:value-of select="string(count(/test/question) > 5)"/>
    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>Here are the string values of some <text> elements:</xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:for-each select="/test/question/text">
      <xsl:text>   </xsl:text>
      <xsl:value-of select="string(.)"/>
      <xsl:value-of select="$newline"/>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

Here are the results of our stylesheet:


Tests of the string() function:

   string(count(/test))=1
   string(count(/test/question))=2
   string('4')=4
   string(true())=true
   string(false())=false
   string(count(/test/question) > 5)=false

Here are the string values of some <text> elements:
   When completed, the Eiffel Tower was the tallest building in the world.
   New York's Empire State Building knocked the Eiffel Tower from its pedestal.
string-length() FunctionReturns the number of characters in the string passed in as the argument to this function. If no argument is specified, the context node is converted to a string and the length of that string is returned.

Synopsis

number string-length(string?)

Inputs

An optional string.

Output

The number of characters defined in the string.

Defined in

XPath section 4.2, String Functions.

Example

The following example demonstrates the results of invoking the string-length() function against various argument types. Here's the XML document we'll use for our example:

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

We'll process this document with the following stylesheet:

<?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 string-length() function:</xsl:text>

    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   string-length(/test)=</xsl:text>
    <xsl:value-of select="string-length(/test)"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   string-length(/true)=</xsl:text>
    <xsl:value-of select="string-length(/true)"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   string-length(//true)=</xsl:text>
    <xsl:value-of select="string-length(//true)"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   string-length(//test|//true|//text)=</xsl:text>
    <xsl:value-of select="string-length(//test|//true|//text)"/>
    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:for-each select="/test/question">
      <xsl:text>   Question #</xsl:text>
      <xsl:value-of select="position()"/>
      <xsl:text> contains </xsl:text>
      <xsl:value-of select="string-length()"/>
      <xsl:text> characters.</xsl:text>
      <xsl:value-of select="$newline"/>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

Here are the results of our stylesheet:


Tests of the string-length() function:

   string-length(/test)=522
   string-length(/true)=0
   string-length(//true)=78
   string-length(//test|//true|//text)=522

   Question #1 contains 239 characters.
   Question #2 contains 203 characters.

When we invoked the string-length() function without any arguments, the context node was converted to a string, then the length of that string was returned. The two <question> elements were handled this way inside the <xsl:for-each> element.

substring() FunctionReturns 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.

Synopsis

string substring(stringnumbernumber?)

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.

substring-after() FunctionReturns the substring of the first argument after the first occurrence of the second argument in the first argument. If the second argument does not occur in the first argument, the substring-after() function returns an empty string.

Synopsis

string substring-after(stringstring)

Inputs

Two strings. The first string is the string to be searched, and the second string is the string to be searched for in the first string.

Output

The portion of the first argument that occurs after the first occurrence of the second argument. If the second argument does not appear in the first argument, the function returns an empty string.

Defined in

XPath section 4.2, String Functions.

Example

This stylesheet uses the replace-substring named template. It passes three arguments to the replace-substring template: the original string, the substring to be searched for in the original string, and the substring to replace the target substring in the original string. The replace-substring template uses the contains(), substring-after(), and substring-before() functions extensively.

Here is our sample stylesheet. It replaces all occurrences of World with the string "Mundo":

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

  <xsl:output method="text"/>

  <xsl:template match="/">
    <xsl:variable name="test">
      <xsl:call-template name="replace-substring">
        <xsl:with-param name="original">Hello World!</xsl:with-param>
        <xsl:with-param name="substring">World</xsl:with-param>
        <xsl:with-param name="replacement">Mundo</xsl:with-param>
      </xsl:call-template>
    </xsl:variable>
    <xsl:value-of select="$test"/>
  </xsl:template>

  <xsl:template name="replace-substring">
    <xsl:param name="original"/>
    <xsl:param name="substring"/>
    <xsl:param name="replacement" select="''"/>
    <xsl:variable name="first">
      <xsl:choose>
        <xsl:when test="contains($original, $substring)">
          <xsl:value-of select="substring-before($original, $substring)"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="$original"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>

    <xsl:variable name="middle">
      <xsl:choose>
        <xsl:when test="contains($original, $substring)">
          <xsl:value-of select="$replacement"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:text></xsl:text>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <xsl:variable name="last">
      <xsl:choose>
        <xsl:when test="contains($original, $substring)">
          <xsl:choose>
            <xsl:when test="contains(substring-after($original, $substring), 
                             $substring)">

              <xsl:call-template name="replace-substring">
                <xsl:with-param name="original">
                  <xsl:value-of 
                    select="substring-after($original, $substring)"/>
                </xsl:with-param>
                <xsl:with-param name="substring">
                  <xsl:value-of select="$substring"/>
                </xsl:with-param>
                <xsl:with-param name="replacement">
                  <xsl:value-of select="$replacement"/>
                </xsl:with-param>
              </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="substring-after($original, $substring)"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:when>
        <xsl:otherwise>
          <xsl:text></xsl:text>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <xsl:value-of select="concat($first, $middle, $last)"/>
  </xsl:template>

</xsl:stylesheet>

The stylesheet produces these results, regardless of the XML document used as input:

Hello Mundo!
substring-before() FunctionReturns the substring of the first argument before the first occurrence of the second argument in the first argument. If the second argument does not occur in the first argument, the substring-before() function returns an empty string.

Synopsis

string substring-before(stringstring)

Inputs

Two strings. The first string is the string to be searched, and the second string is the string to be searched for in the first string.

Output

The portion of the first argument that occurs before the first occurrence of the second argument. If the second argument does not appear in the first argument, the function returns an empty string.

Defined in

XPath section 4.2, String Functions.

Example

This stylesheet uses the replace-substring named template. It passes three arguments to the replace-substring template: the original string, the substring to be searched for in the original string, and the substring to replace the target substring in the original string. The replace-substring template uses the contains(), substring-after(), and substring-before() functions extensively.

Here is our sample stylesheet. It replaces all occurrences of World with the string "Mundo":

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

  <xsl:output method="text"/>

  <xsl:template match="/">
    <xsl:variable name="test">
      <xsl:call-template name="replace-substring">
        <xsl:with-param name="original">Hello World!</xsl:with-param>
        <xsl:with-param name="substring">World</xsl:with-param>
        <xsl:with-param name="replacement">Mundo</xsl:with-param>
      </xsl:call-template>
    </xsl:variable>
    <xsl:value-of select="$test"/>
  </xsl:template>

  <xsl:template name="replace-substring">
    <xsl:param name="original"/>
    <xsl:param name="substring"/>
    <xsl:param name="replacement" select="''"/>
    <xsl:variable name="first">
      <xsl:choose>
        <xsl:when test="contains($original, $substring)">
          <xsl:value-of select="substring-before($original, $substring)"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="$original"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <xsl:variable name="middle">
      <xsl:choose>
        <xsl:when test="contains($original, $substring)">
          <xsl:value-of select="$replacement"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:text></xsl:text>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <xsl:variable name="last">
      <xsl:choose>
        <xsl:when test="contains($original, $substring)">
          <xsl:choose>
            <xsl:when test="contains(substring-after($original, $substring), 
                                      $substring)">
              <xsl:call-template name="replace-substring">
                <xsl:with-param name="original">
                  <xsl:value-of 
                    select="substring-after($original, $substring)"/>
                </xsl:with-param>
                <xsl:with-param name="substring">
                  <xsl:value-of select="$substring"/>
                </xsl:with-param>
                <xsl:with-param name="replacement">
                  <xsl:value-of select="$replacement"/>
                </xsl:with-param>
              </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="substring-after($original, $substring)"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:when>
        <xsl:otherwise>
          <xsl:text></xsl:text>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <xsl:value-of select="concat($first, $middle, $last)"/>
  </xsl:template>

</xsl:stylesheet>

The stylesheet produces these results, regardless of the XML document used as input:

Hello Mundo!
sum() FunctionConverts all nodes in the argument node-set to numbers, and then returns the sum of all of those numbers. If any node in the node-set can't be converted to numbers (passing them to the number() function returns NaN), the sum() function returns NaN.

Synopsis

number sum(node-set)

Inputs

A node-set. Any node in the node-set that is not a number is converted to a number as if it were passed to the number() function, then the numeric values of all of the nodes are summed.

Output

The sum of the numeric values of all of the nodes in the argument node-set. If any node in the argument node-set cannot be converted to a number, the sum() function returns NaN.

Defined in

XPath section 4.4, Number Functions.

Example

We'll demonstrate the sum() function against the following XML document:

<?xml version="1.0"?>
<report>
  <title>Miles Flown in 2001</title>
  <month sequence="01">
    <miles-flown>12379</miles-flown>
    <miles-earned>35215</miles-earned>
  </month>
  <month sequence="02">
    <miles-flown>32857</miles-flown>
    <miles-earned>92731</miles-earned>
  </month>
  <month sequence="03">
    <miles-flown>19920</miles-flown>
    <miles-earned>76725</miles-earned>
  </month>
  <month sequence="04">
    <miles-flown>18903</miles-flown>
    <miles-earned>31781</miles-earned>
  </month>
</report>

Here is a stylesheet that uses the sum() function:

<?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>A test of the sum() function:</xsl:text>

    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>Total miles flown this year:  </xsl:text>
    <xsl:value-of 
      select="format-number(sum(/report/month/miles-flown), '###,###')"/>
    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>Total miles earned this year: </xsl:text>
    <xsl:value-of 
      select="format-number(sum(/report/month/miles-earned), '###,###')"/>
    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
  </xsl:template>

</xsl:stylesheet>

Processing the XML document with this stylesheet generates these results:


A test of the sum() function:

Total miles flown this year:  84,059

Total miles earned this year: 236,452
system-property() FunctionReturns the value of the system property named by the argument to the function.

Synopsis

object system-property(string)

Description

By definition, all XSLT processors must support three system properties:

xsl:version
A floating-point number representing the version of XSLT implemented by this XSLT processor. As of this writing, the only official version of XSLT supported by any XSLT processors is 1.0.

xsl:vendor
A string that identifies the vendor of this XSLT processor.

xsl:vendor-url
A string containing the URL identifying the vendor of the XSLT processor. This string is typically the home page of the vendor's web site.

Inputs

The XSLT 1.0 specification defines three properties: xsl:version, xsl:vendor, and xsl:vendor-url. These properties must be supported by all XSLT processors. Other properties may be supported by individual processors; check your processor's documentation for more information.

Output

The value of the queried property.

Defined in

XSLT section 12.4, Miscellaneous Additional Functions.

Example

Here is a stylesheet that queries different properties of the XSLT processor:

<?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:text>xsl:version = "</xsl:text>
    <xsl:value-of select="system-property('xsl:version')"/>
    <xsl:text>"</xsl:text><xsl:value-of select="$newline"/>
    <xsl:text>xsl:vendor = "</xsl:text>
    <xsl:value-of select="system-property('xsl:vendor')"/>
    <xsl:text>"</xsl:text><xsl:value-of select="$newline"/>
    <xsl:text>xsl:vendor-url = "</xsl:text>

    <xsl:value-of select="system-property('xsl:vendor-url')"/>
    <xsl:text>"</xsl:text><xsl:value-of select="$newline"/>
  </xsl:template>

</xsl:stylesheet>

When the stylesheet is applied toward any XML document with the Xalan XSLT processor (invoked by the following command):

java org.apache.xalan.xslt.Process -in test1.xml -xsl systemproperties.xsl

The results are:

xsl:version = "1"
xsl:vendor = "Apache Software Foundation"
xsl:vendor-url = "http://xml.apache.org/xalan"

The following command invokes the results for Michael Kay's Saxon processor:

java com.icl.saxon.StyleSheet test1.xml systemproperties.xsl

Here are the results:

xsl:version = "1"                                                      
xsl:vendor = "SAXON 6.4.3 from Michael Kay"                     
xsl:vendor-url = "http://saxon.sourceforge.net"

We invoked Oracle's XML parser with:

java oracle.xml.parser.v2.oraxsl test1.xml systemproperties.xsl

Here are the results:

xsl:version = "1"
xsl:vendor = "Oracle Corporation."
xsl:vendor-url = "http://www.oracle.com"

We invoked James Clark's XT processor with:

java com.jclark.xsl.sax.Driver test1.xml systemproperties.xsl

Here are the results:

xsl:version = "1"
xsl:vendor = "James Clark"
xsl:vendor-url = "http://www.jclark.com/"

Finally, we invoked Microsoft's XSLT processor with:

Synopsis

msxsl test1.xml systemproperties.xsl

Here are the results:

xsl:version = "1"
xsl:vendor = "Microsoft"
xsl:vendor-url = "http://www.microsoft.com"
translate() FunctionAllows you to convert individual characters in a string from one value to another. In many languages, this function is powerful enough to convert characters from one case to another.

Synopsis

string translate(stringstringstring)

Inputs

Three strings. The first is the original, untranslated string, and the second and third strings define the characters to be converted.

Output

The original string, translated as follows:

  • If a character in the original string appears in the second argument string, it is replaced with the corresponding character in the third argument string. In other words, if the character J appears in the original string and J appears as the fourth character in the second argument string, the J is replaced with the fourth character from the third argument string. (Don't worry, we'll have some examples to clear this up in just a minute.)

  • If a character in the original string appears in the second argument string and there is no corresponding character in the third argument string (the second argument string is longer than the third), then that character is deleted. In other words, if the character J appears in the original string, and J appears as the fourth character in the second argument string, and the third argument string is three characters long, the J is deleted.

  • If a character in the second argument string appears more than once, the first occurrence determines the replacement character.

  • If the third argument string is longer than the second argument string, the extra characters are ignored.

Defined in

XPath section 4.2, String Functions.

Example

Here's a stylesheet with several examples of the translate() function:

<?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 translate() function:</xsl:text>

    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>Convert a string to uppercase:</xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:text>   translate('Doug', 'abcdefghijklmnopqrstuvwxyz', </xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:text>             'ABCDEFGHIJKLMNOPQRSTUVWXYZ')=</xsl:text>
    <xsl:value-of select="translate('Doug', 
      'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/>
    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>Convert a string to lowercase:</xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:text>   translate('Doug', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', </xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:text>             'abcdefghijklmnopqrstuvwxyz')=</xsl:text>
    <xsl:value-of 
      select="translate('Doug', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
                        'abcdefghijklmnopqrstuvwxyz')"/>
    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>Remove parentheses, spaces, and dashes</xsl:text>
    <xsl:text> from a U.S. phone number:</xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:text>   translate('(555) 555-1212', '() -', '')=</xsl:text>
    <xsl:value-of select="translate('(555) 555-1212', '() -', '')"/>
    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>Replace all but the last four digits of a </xsl:text>
    <xsl:text>credit card number with Xs:</xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:variable name="credit" select="'4918 3829 9920 1810'"/>
    <xsl:text>   $credit='</xsl:text>
    <xsl:value-of select="$credit"/>
    <xsl:text>'</xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:text>   translate(substring($credit, 1, 15), </xsl:text>
    <xsl:text>'1234567890 ', 'XXXXXXXXXX-')</xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:text>   substring($credit, 16)</xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   The first part is </xsl:text>
    <xsl:value-of 
      select="translate(substring($credit, 1, 15), '123457890 ', 
        'XXXXXXXXX-')"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   The second part is </xsl:text>
    <xsl:value-of select="substring($credit, 16)"/>
    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   Here's how they look together: </xsl:text>
    <xsl:value-of 
      select="translate(substring($credit, 1, 15), '123457890 ', 
        'XXXXXXXXX-')"/>
    <xsl:value-of select="substring($credit, 16)"/>
  </xsl:template>

</xsl:stylesheet>

When we use this stylesheet with any XML document, here are the results:


Tests of the translate() function:

Convert a string to uppercase:
   translate('Doug', 'abcdefghijklmnopqrstuvwxyz',
             'ABCDEFGHIJKLMNOPQRSTUVWXYZ')=DOUG

Convert a string to lowercase:
   translate('Doug', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
             'abcdefghijklmnopqrstuvwxyz')=doug

Remove parentheses, spaces, and dashes from a U.S. phone number:
   translate('(555) 555-1212', '() -', '')=5555551212

Replace all but the last four digits of a credit card number with Xs:
   $credit='4918 3829 9920 1810'
   translate(substring($credit, 1, 15), '1234567890 ', 'XXXXXXXXXX-')
   substring($credit, 16)

   The first part is XXXX-XXXX-XXXX-
   The second part is 1810

   Here's how they look together: XXXX-XXXX-XXXX-1810
true() FunctionAlways returns the boolean value true.

Synopsis

boolean true()

Inputs

None.

Output

The boolean value true.

Defined in

XPath section 4.3, Boolean Functions.

Example

Here's a brief example that uses the true() function:

<?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>A test of the true() function:</xsl:text>

    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:choose>
      <xsl:when test="true()">
        <xsl:text>   "true()"   returned true!</xsl:text>
      </xsl:when>
      <xsl:otherwise>
        <xsl:text>   "true()"   returned false!</xsl:text>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

When using this stylesheet against any XML document, it generates this less-than-exciting result:


A test of the true() function:

   "true()"   returned true!
unparsed-entity-uri() FunctionReturns the URI of the unparsed entity with the specified name. If there is no such entity, unparsed-entity-uri returns an empty string.

Synopsis

string unparsed-entity-uri(string)

Inputs

The name of the unparsed entity.

Output

The URI of the unparsed entity with the specified name.

Defined in

XSLT section 12.4, Miscellaneous Additional Functions.

Example

Unparsed entities are rarely used; they refer to non-XML data, as in the entity author-picture in this XML document:

<?xml version="1.0"?>
<!DOCTYPE book [
  <!ENTITY author-picture SYSTEM "dougtidwell.jpg" NDATA JPEG>
]>
<book>
  <prolog cover-image="author-picture"/>
  <body>
    <p>Pretend that lots of useful content appears here.</p>
  </body>
</book>

We'll use this stylesheet to process our unparsed entity:

<?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>A test of the unparsed-entity-uri() function:</xsl:text>

    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>   The cover image is located at </xsl:text>
    <xsl:value-of select="unparsed-entity-uri(/book/prolog/@cover-image)"/>
    <xsl:text>.</xsl:text>
    <xsl:value-of select="$newline"/>
  </xsl:template>

</xsl:stylesheet>

When we transform the XML document with our stylesheet, the results look like this:


A test of the unparsed-entity-uri() function:

   The cover image is located at file:///D:/O'Reilly/dougtidwell.jpg.

The URI of the unparsed entity is based on the base URI of the XML document itself.



Library Navigation Links

Copyright © 2002 O'Reilly & Associates. All rights reserved.