This section lists all functions defined by XSLT and XPath.
boolean() Function | Converts its argument to a boolean value. |
boolean boolean(object)
An object. The object is converted to a boolean value. This conversion is described in the following subsection.
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.
XPath section 4.3, Boolean Functions.
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() Function | Returns the smallest integer that is not less than the argument. |
number ceiling(number)
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).
The smallest integer that is not less than the argument, or NaN if the argument cannot be converted to a number.
XPath section 4.4, Number Functions.
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() Function | Takes all of its arguments and concatenates them. Any arguments that are not strings are converted to strings as if processed by the string() function. |
string concat(stringstringstring*)
Two or more strings.
The concatenation of all of the input strings.
XPath section 4.2, String Functions.
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() Function | Determines if the first argument string contains the second. |
boolean contains(stringstring)
Two strings. If the first string contains the second string, the function returns the boolean value true.
The boolean value true if the first argument contains the second; false otherwise.
XPath section 4.2, String Functions.
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() Function | Counts the number of nodes in a given node-set. |
number count(node-set)
A node-set.
The number of nodes in the node-set.
XPath section 4.1, Node Set Functions.
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() Function | Returns a node-set that has the current node as its only member. |
node-set current()
None.
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.
XSLT section 12.4, Miscellaneous Additional Functions.
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() Function | Allows 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. |
node-set document(objectnode-set?)
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.
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.
XSLT section 12.1, Multiple Source Documents.
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() Function | Determines 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. |
boolean element-available(string)
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.
The boolean value true if the element is available; false otherwise.
XSLT section 15, Fallback.
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.
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.
In this example, the element-available() function allows us to determine what processing capabilities are available and respond gracefully to whatever we find.
false() Function | Always 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. |
boolean false()
None.
The boolean value false.
XPath section 4.3, Boolean Functions.
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() Function | Returns the largest integer that is not greater than the argument. |
number floor(number)
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).
The largest integer that is not greater than the argument, or NaN if the argument cannot be converted into a number.
XPath section 4.4, Number Functions.
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() Function | Takes a number and formats it as a string. |
string format-number(numberstringstring?)
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.
The number, formatted according to the rules supplied by the other arguments. The special characters used in the second argument are:
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.
XSLT section 12.3, Number Formatting.
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() Function | Determines 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. |
boolean function-available(string)
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.
The boolean value true if the function is available, false otherwise.
XSLT section 15, Fallback.
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.
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() Function | Generates 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. |
string generate-id(node-set?)
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.
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.
XSLT section 12.4, Miscellaneous Additional Functions.
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() Function | Returns the node in the source tree whose ID attribute matches the value passed in as input. |
node-set id(object)
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.
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.
XPath section 4.1, Node Set Functions.
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.
key() Function | References 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. |
node-set key(stringobject)
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.
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.
XSLT section 12.2, Keys.
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:
<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.
lang() Function | Determines 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. |
boolean lang(string)
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.
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.
XPath section 4.3, Boolean Functions.
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() Function | Returns 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. |
number last()
None.
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.
XPath section 4.1, Node Set Functions.
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.
local-name() Function | Returns the local part of the first node in the argument node-set. |
string local-name(node-set?)
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.
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.
XPath section 4.1, Node Set Functions.
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() Function | Returns 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. |
string name(node-set?)
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.
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.
XPath section 4.1, Node Set Functions.
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() Function | Returns the namespace URI of the first node in the argument node-set. |
string namespace-uri(node-set?)
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.
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.
XPath section 4.1, Node Set Functions.
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() Function | Removes extra whitespace from its argument string. |
string normalize-space(string?)
An optional string. If the argument is omitted, the normalize-space() function uses the string value of the context node.
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.
XPath section 4.2, String Functions.
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() Function | Returns 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. |
boolean not(boolean)
A boolean value, or more commonly, an XPath expression that evaluates to a boolean value.
false if the input parameter is true; true if the input parameter is false.
XPath section 4.3, Boolean Functions.
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() Function | Converts its argument to a number. |
number number(object?)
An object. The object is converted to a number as described in the following subsection.
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.
XPath section 4.4, Number Functions.
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() Function | Returns a number equal to the context position from the current context. |
number position()
None.
A number equal to the position of the current node in the evaluation context.
XPath section 4.1, Node Set Functions.
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.
round() Function | Returns the integer closest to the argument. |
number round(number)
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.
A number. If the argument is not a number, it is converted to a number as if it were passed to the number() function.
The integer that is closest to the argument. Special cases are handled as described in this section.
XPath section 4.4, Number Functions.
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() Function | Determines if the first argument string begins with the second argument. |
boolean starts-with(stringstring)
Two strings.
If the first string begins with the second, starts-with() returns the boolean value true; otherwise it returns false.
XPath section 4.2, String Functions.
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() Function | Returns the string value of the argument. |
string string(object)
An object. The object is converted to a string, as described in the following subsection.
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.
XPath section 4.2, String Functions.
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() Function | Returns 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. |
number string-length(string?)
An optional string.
The number of characters defined in the string.
XPath section 4.2, String Functions.
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() Function | Returns a portion of a given string. The second and third arguments determine what portion of the string is returned. The second argument specifies the position of the first character of the substring, and the optional third argument specifies how many characters should be returned. |
string substring(stringnumbernumber?)
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.
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.
XPath section 4.2, String Functions.
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() Function | Returns 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. |
string substring-after(stringstring)
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.
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.
XPath section 4.2, String Functions.
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() Function | Returns 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. |
string substring-before(stringstring)
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.
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.
XPath section 4.2, String Functions.
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() Function | Converts 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. |
number sum(node-set)
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.
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.
XPath section 4.4, Number Functions.
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() Function | Returns the value of the system property named by the argument to the function. |
object system-property(string)
By definition, all XSLT processors must support three system properties:
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.
The value of the queried property.
XSLT section 12.4, Miscellaneous Additional Functions.
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:
msxsl test1.xml systemproperties.xsl
Here are the results:
xsl:version = "1" xsl:vendor = "Microsoft" xsl:vendor-url = "http://www.microsoft.com"
translate() Function | Allows 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. |
string translate(stringstringstring)
Three strings. The first is the original, untranslated string, and the second and third strings define the characters to be converted.
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.
XPath section 4.2, String Functions.
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() Function | Always returns the boolean value true. |
boolean true()
None.
The boolean value true.
XPath section 4.3, Boolean Functions.
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() Function | Returns the URI of the unparsed entity with the specified name. If there is no such entity, unparsed-entity-uri returns an empty string. |
string unparsed-entity-uri(string)
The name of the unparsed entity.
The URI of the unparsed entity with the specified name.
XSLT section 12.4, Miscellaneous Additional Functions.
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.
Copyright © 2002 O'Reilly & Associates. All rights reserved.