Appendix C. XSLT and XPath Function ReferenceThis section lists all functions defined by XSLT and XPath.
Synopsisboolean boolean(object) InputsAn object. The object is converted to a boolean value. This conversion is described in the following subsection. OutputThe boolean value corresponding to the input object. Objects are converted to boolean values as follows:
Defined inXPath section 4.3, Boolean Functions. ExampleThe 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.
Synopsisnumber ceiling(number) InputsA 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). OutputThe smallest integer that is not less than the argument, or NaN if the argument cannot be converted to a number. Defined inXPath section 4.4, Number Functions. ExampleThe 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.
Synopsisstring concat(stringstringstring*) InputsTwo or more strings. OutputThe concatenation of all of the input strings. Defined inXPath section 4.2, String Functions. ExampleWe'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
Synopsisboolean contains(stringstring) InputsTwo strings. If the first string contains the second string, the function returns the boolean value true. OutputThe boolean value true if the first argument contains the second; false otherwise. Defined inXPath section 4.2, String Functions. ExampleThis 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!
Synopsisnumber count(node-set) InputsA node-set. OutputThe number of nodes in the node-set. Defined inXPath section 4.1, Node Set Functions. ExamplesHere'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.
Synopsisnode-set current() InputsNone. OutputA node-set that has the current node as its only member. Most of the time, the current node is no different than the context node. These two XSLT elements have the same meaning: <xsl:value-of select="current()"/> <xsl:value-of select="."/> Within a predicate expression, however, the current node and the context node are usually different. The example section that follows illustrates when you need to use the current() function. Defined inXSLT section 12.4, Miscellaneous Additional Functions. ExampleWe'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.
Synopsisnode-set document(objectnode-set?) InputsThe 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. OutputA node-set containing the nodes identified by the input argument. Again, Chapter 7, "Combining XML Documents" has all the details, so we won't rehash them here. Defined inXSLT section 12.1, Multiple Source Documents. ExampleThe 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.)
Synopsisboolean element-available(string) InputsThe 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. OutputThe boolean value true if the element is available; false otherwise. Defined inXSLT section 15, Fallback. ExampleWe'll use the following example to test the element-available() function: <?xml version="1.0"?> <book> <title>XSLT</title> <chapter> <title>Getting Started</title> <para>If this chapter had any text, it would appear here.</para> </chapter> <chapter> <title>The Hello World Example</title> <para>If this chapter had any text, it would appear here.</para> </chapter> <chapter> <title>XPath</title> <para>If this chapter had any text, it would appear here.</para> </chapter> <chapter> <title>Stylesheet Basics</title> <para>If this chapter had any text, it would appear here.</para> </chapter> <chapter> <title>Branching and Control Elements</title> <para>If this chapter had any text, it would appear here.</para> </chapter> <chapter> <title>Functions</title> <para>If this chapter had any text, it would appear here.</para> </chapter> <chapter> <title>Creating Links and Cross-References</title> <para>If this chapter had any text, it would appear here.</para> </chapter> <chapter> <title>Sorting and Grouping Elements</title> <para>If this chapter had any text, it would appear here.</para> </chapter> <chapter> <title>Combining XML Documents</title> <para>If this chapter had any text, it would appear here.</para> </chapter> </book> Here is our stylesheet: <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:redirect="org.apache.xalan.xslt.extensions.Redirect" xmlns:saxon="http://icl.com/saxon" extension-element-prefixes="redirect saxon"> <xsl:output method="html"/> <xsl:template match="/"> <xsl:choose> <xsl:when test="element-available('redirect:write')"> <xsl:for-each select="/book/chapter"> <redirect:write select="concat('chapter', position(), '.html')"> <html> <head> <title><xsl:value-of select="title"/></title> </head> <body> <h1><xsl:value-of select="title"/></h1> <xsl:apply-templates select="para"/> <xsl:if test="not(position()=1)"> <p> <a href="chapter{position()-1}.html">Previous</a> </p> </xsl:if> <xsl:if test="not(position()=last())"> <p> <a href="chapter{position()+1}.html">Next</a> </p> </xsl:if> </body> </html> </redirect:write> </xsl:for-each> </xsl:when> <xsl:when test="element-available('saxon:output')"> <xsl:for-each select="/book/chapter"> <saxon:output file="chapter{position()}.html"> <html> <head> <title><xsl:value-of select="title"/></title> </head> <body> <h1><xsl:value-of select="title"/></h1> <xsl:apply-templates select="para"/> <xsl:if test="not(position()=1)"> <p> <a href="chapter{position()-1}.html">Previous</a> </p> </xsl:if> <xsl:if test="not(position()=last())"> <p> <a href="chapter{position()+1}.html">Next</a> </p> </xsl:if> </body> </html> </saxon:output> </xsl:for-each> </xsl:when> <xsl:otherwise> <html> <head> <title><xsl:value-of select="/book/title"/></title> </head> <xsl:for-each select="/book/chapter"> <h1><xsl:value-of select="title"/></h1> <xsl:apply-templates select="para"/> </xsl:for-each> </html> </xsl:otherwise> </xsl:choose> <xsl:if test="not(element-available('write'))"> <xsl:message terminate="no"> The <write> element is not available! </xsl:message> </xsl:if> </xsl:template> <xsl:template match="para"> <p><xsl:apply-templates select="*|text()"/></p> </xsl:template> </xsl:stylesheet> This stylesheet attempts to take the content in the XML file and write portions of it out to different HTML files. The first <chapter> element is written to the file chapter1.html, the second <chapter> element is written to the file chapter2.html, and so on. Our stylesheet attempts to use Xalan's <redirect:write> element first; if that element is not available, it checks for Saxon's <saxon:output> element. If neither of those elements is available, it writes the contents of all <chapter> elements to the same output stream. The stylesheet also calls the element-available() function with the nonqualified element name write; this call always returns false because the element name is not namespace qualified. When we use Xalan to process the XML file with our stylesheet, here are the results on the console: file:///D:/O'Reilly/XSLT/bookSamples/AppendixC/elementavailable.xsl; Line 66; Column 35; The <write> element is not available! The stylesheet generates the files chapter1.html through chapter9.html, with each file containing data from one of the <chapter> elements in the original file. Our stylesheet also generates hyperlinks between the chapter files; here's what chapter3.html looks like: <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>XPath</title> </head> <body> <h1>XPath</h1> <p>If this chapter had any text, it would appear here.</p> <p><a href="chapter2.html">Previous</a></p> <p><a href="chapter4.html">Next</a></p> </body> </html> When rendered in a browser, the file looks like Figure C-1. Figure C-1. Sample HTML output fileClicking on the Previous link takes you to the file chapter2.html, while clicking on the Next link takes you to chapter4.html. Using our stylesheet with Saxon (using the command java com.icl.saxon.StyleSheet chapterlist.xml elementavailable.xsl) produces similar results on the console: The <write> element is not available! Although the format of the message is slightly different, the output in the multiple HTML files is the same. Finally, if we use the Oracle XML parser, none of the elements we query will be available, so all the output is written to a single file. We'll invoke the processor with this command. (The command should be on one line.) java oracle.xml.parser.v2.oraxsl chapterlist.xml elementavailable.xsl chapters.html Here's the console output: Message: The <write> element is not available! The output file, chapters.html, looks like this: <html xmlns:redirect="org.apache.xalan.xslt.extensions.Redirect" xmlns:saxon="http://icl.com/saxon"> <head> <META http-equiv="Content-Type" content="text/html"> <title>XSLT</title> </head> <h1>Getting Started</h1> <p>If this chapter had any text, it would appear here.</p> <h1>The Hello World Example</h1> <p>If this chapter had any text, it would appear here.</p> <h1>XPath</h1> <p>If this chapter had any text, it would appear here.</p> <h1>Stylesheet Basics</h1> <p>If this chapter had any text, it would appear here.</p> <h1>Branching and Control Elements</h1> <p>If this chapter had any text, it would appear here.</p> <h1>Functions</h1> <p>If this chapter had any text, it would appear here.</p> <h1>Creating Links and Cross-References</h1> <p>If this chapter had any text, it would appear here.</p> <h1>Sorting and Grouping Elements</h1> <p>If this chapter had any text, it would appear here.</p> <h1>Combining XML Documents</h1> <p>If this chapter had any text, it would appear here.</p> </html> When rendered, our output looks like Figure C-2. Figure C-2. HTML document listing all chaptersIn this example, the element-available() function allows us to determine what processing capabilities are available and respond gracefully to whatever we find.
Synopsisboolean false() InputsNone. OutputThe boolean value false. Defined inXPath section 4.3, Boolean Functions. ExampleHere'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!
Synopsisnumber floor(number) InputsA 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). OutputThe largest integer that is not greater than the argument, or NaN if the argument cannot be converted into a number. Defined inXPath section 4.4, Number Functions. ExampleThe 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.
Synopsisstring format-number(numberstringstring?) InputsThe 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. OutputThe 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. Defined inXSLT section 12.3, Number Formatting. ExampleThe 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.
Synopsisboolean function-available(string) InputsThe 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. OutputThe boolean value true if the function is available, false otherwise. Defined inXSLT section 15, Fallback. ExampleWe'll use the following XML document to test the function-available() function: <?xml version="1.0"?> <list> <title>A few of my favorite albums</title> <listitem>A Love Supreme</listitem> <listitem>Beat Crazy</listitem> <listitem>Here Come the Warm Jets</listitem> <listitem>Kind of Blue</listitem> <listitem>London Calling</listitem> <listitem>Remain in Light</listitem> <listitem>The Joshua Tree</listitem> <listitem>The Indestructible Beat of Soweto</listitem> </list> Here's our stylesheet: <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:jpeg="class:JPEGWriter" extension-element-prefixes="jpeg"> <xsl:output method="text"/> <xsl:variable name="newline"> <xsl:text> </xsl:text> </xsl:variable> <xsl:template match="/"> <xsl:value-of select="$newline"/> <xsl:for-each select="list/listitem"> <xsl:choose> <xsl:when test="function-available('jpeg:createJPEG')"> <xsl:value-of select="jpeg:createJPEG(., 'bg.jpg', concat('album', position(), '.jpg'), 'Swiss 721 Bold Condensed', 'BOLD', 22, 52, 35)"/> <xsl:text>See the file </xsl:text> <xsl:value-of select="concat('album', position(), '.jpg')"/> <xsl:text> to see the title of album #</xsl:text> <xsl:value-of select="position()"/> <xsl:value-of select="$newline"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="position()"/> <xsl:text>. </xsl:text> <xsl:value-of select="."/> <xsl:value-of select="$newline"/> </xsl:otherwise> </xsl:choose> </xsl:for-each> </xsl:template> </xsl:stylesheet> In our stylesheet, if the createJPEG() function is available, we'll invoke it to create JPEG files for the titles of all our favorite albums. If the function is not available, we'll simply write those titles to the output stream. Here are the results we get when the createJPEG() function is available: See the file album1.jpg to see the title of album #1 See the file album2.jpg to see the title of album #2 See the file album3.jpg to see the title of album #3 See the file album4.jpg to see the title of album #4 See the file album5.jpg to see the title of album #5 See the file album6.jpg to see the title of album #6 See the file album7.jpg to see the title of album #7 See the file album8.jpg to see the title of album #8 All album titles (the text of the <listitem> elements) are converted to JPEG graphics. In this example, the file album8.jpg looks like Figure C-3. Figure C-3. Generated graphic for the eighth <listitem> elementIf 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
Synopsisstring generate-id(node-set?) InputsAn 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. OutputA unique ID, or an empty string if an empty node-set is given. Several things about the generate-id() function are important to know:
Defined inXSLT section 12.4, Miscellaneous Additional Functions. ExampleHere'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.
Synopsisnode-set id(object) InputsAn 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. OutputA node-set containing all nodes whose attributes of type ID match the string values of the input node-set. In practice, this node-set is a single node, the node whose attribute of type ID matches a string value. Defined inXPath section 4.1, Node Set Functions. ExampleFor our example, we'll take this shortened version of the glossary we discussed earlier: <?xml version="1.0" ?> <!DOCTYPE glossary SYSTEM "glossary.dtd"> <glossary> <glentry> <term id="applet">applet</term> <defn> An application program, written in the Java programming language, that can be retrieved from a web server and executed by a web browser. A reference to an applet appears in the markup for a web page, in the same way that a reference to a graphics file appears; a browser retrieves an applet in the same way that it retrieves a graphics file. For security reasons, an applet's access rights are limited in two ways: the applet cannot access the filesystem of the client upon which it is executing, and the applet's communication across the network is limited to the server from which it was downloaded. Contrast with <xref refid="servlet"/>. </defn> </glentry> <glentry> <term id="servlet">servlet</term> <defn> An application program, written in the Java programming language, that is executed on a web server. A reference to a servlet appears in the markup for a web page, in the same way that a reference to a graphics file appears. The web server executes the servlet and sends the results of the execution (if there are any) to the web browser. Contrast with <xref refid="applet" />. </defn> </glentry> </glossary> Here's the stylesheet we'll use to resolve the references: <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:template match="/"> <xsl:apply-templates select="glossary"/> </xsl:template> <xsl:template match="glossary"> <html> <head> <title> <xsl:text>Glossary Listing </xsl:text> </title> </head> <body> <h1> <xsl:text>Glossary Listing </xsl:text> </h1> <xsl:apply-templates select="glentry"/> </body> </html> </xsl:template> <xsl:template match="glentry"> <p> <b> <a> <xsl:attribute name="name"> <xsl:value-of select="term/@id" /> </xsl:attribute> </a> <xsl:value-of select="term"/> <xsl:text>: </xsl:text> </b> <xsl:apply-templates select="defn"/> </p> </xsl:template> <xsl:template match="defn"> <xsl:apply-templates select="*|comment()|processing-instruction()|text()"/> </xsl:template> <xsl:template match="xref"> <a> <xsl:attribute name="href"> <xsl:text>#</xsl:text><xsl:value-of select="@refid"/> </xsl:attribute> <xsl:choose> <xsl:when test="id(@refid)/@xreftext"> <xsl:value-of select="id(@refid)/@xreftext"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="id(@refid)"/> </xsl:otherwise> </xsl:choose> </a> </xsl:template> </xsl:stylesheet> Our stylesheet generates these results: <html> <head> <META http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Glossary Listing </title> </head> <body> <h1>Glossary Listing </h1> <p> <b><a name="applet"></a>applet: </b> An application program, written in the Java programming language, that can be retrieved from a web server and executed by a web browser. A reference to an applet appears in the markup for a web page, in the same way that a reference to a graphics file appears; a browser retrieves an applet in the same way that it retrieves a graphics file. For security reasons, an applet's access rights are limited in two ways: the applet cannot access the filesystem of the client upon which it is executing, and the applet's communication across the network is limited to the server from which it was downloaded. Contrast with <a href="#servlet">servlet</a>. </p> <p> <b><a name="servlet"></a>servlet: </b> An application program, written in the Java programming language, that is executed on a web server. A reference to a servlet appears in the markup for a web page, in the same way that a reference to a graphics file appears. The web server executes the servlet and sends the results of the execution (if there are any) to the web browser. Contrast with <a href="#applet">applet</a>. </p> </body> </html> When rendered in a browser, our hyperlinked document looks like Figure C-4. Figure C-4. Generated HTML glossary
Synopsisnode-set key(stringobject) InputsThe 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. OutputA node-set containing the nodes in the same document as the context node whose values for the requested key match the search argument(s). In other words, if our stylesheet has an <xsl:key> element that defines a key named postalcodes based on the <postalcode> child of all <address> elements in the current document, the function call key(postalcodes, '34829') returns a node-set containing all the <address> elements with a <postalcode> element whose value is 34829. Defined inXSLT section 12.2, Keys. ExampleTo illustrate the power of the key() function, we'll use this document -- a truncated version of the glossary we discussed in Chapter 5, "Creating Links and Cross-References": <?xml version="1.0" ?> <glossary> <glentry> <term id="applet">applet</term> <defn topic="Java" language="en"> An application program, written in the Java programming language, that can be retrieved from a web server and executed by a web browser. A reference to an applet appears in the markup for a web page, in the same way that a reference to a graphics file appears; a browser retrieves an applet in the same way that it retrieves a graphics file. For security reasons, an applet's access rights are limited in two ways: the applet cannot access the filesystem of the client upon which it is executing, and the applet's communication across the network is limited to the server from which it was downloaded. Contrast with <xref refid="servlet"/>. </defn> <defn topic="Java" language="it"> [Pretend this is an Italian definition of applet.] </defn> <defn topic="Java" language="es"> [Pretend this is a Spanish definition of applet.] </defn> </glentry> <glentry> <term id="DMZlong" xreftext="demilitarized zone">demilitarized zone (DMZ)</term> <defn topic="security" language="en"> In network security, a network that is isolated from, and serves as a neutral zone between, a trusted network (for example, a private intranet) and an untrusted network (for example, the Internet). One or more secure gateways usually control access to the DMZ from the trusted or the untrusted network. </defn> <defn topic="security" language="it"> [Pretend this is an Italian definition of DMZ.] </defn> <defn topic="security" language="es"> [Pretend this is a Spanish definition of DMZ.] </defn> <defn topic="security" language="jp"> [Pretend this is a Japanese definition of DMZ.] </defn> <defn topic="security" language="de"> [Pretend this is a German definition of DMZ.] </defn> </glentry> <glentry> <term id="servlet">servlet</term> <defn topic="Java" language="en"> An application program, written in the Java programming language, that is executed on a web server. A reference to a servlet appears in the markup for a web page, in the same way that a reference to a graphics file appears. The web server executes the servlet and sends the results of the execution (if there are any) to the web browser. Contrast with <xref refid="applet" />. </defn> <defn topic="Java" language="es"> [Pretend this is a Spanish definition of servlet.] </defn> <defn topic="Java" language="it"> [Pretend this is an Italian definition of servlet.] </defn> <defn topic="Java" language="de"> [Pretend this is a German definition of servlet.] </defn> <defn topic="Java" language="jp"> [Pretend this is a Japanese definition of servlet.] </defn> </glentry> </glossary> Here's the stylesheet we'll use to process this document. Notice that we define two <xsl:key> elements to index the XML document in two different ways: <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:key name="language-index" match="defn" use="@language"/> <xsl:key name="term-ids" match="term" use="@id"/> <xsl:param name="targetLanguage"/> <xsl:template match="/"> <xsl:apply-templates select="glossary"/> </xsl:template> <xsl:template match="glossary"> <html> <head> <title> <xsl:text>Glossary Listing: </xsl:text> </title> </head> <body> <h1> <xsl:text>Glossary Listing: </xsl:text> </h1> <xsl:for-each select="key('language-index', $targetLanguage)"> <xsl:apply-templates select="ancestor::glentry"/> </xsl:for-each> </body> </html> </xsl:template> <xsl:template match="glentry"> <p> <b> <a> <xsl:attribute name="name"> <xsl:value-of select="term/@id" /> </xsl:attribute> </a> <xsl:value-of select="term"/> <xsl:text>: </xsl:text> </b> <xsl:apply-templates select="defn[@language=$targetLanguage]"/> </p> </xsl:template> <xsl:template match="defn"> <xsl:apply-templates select="*|comment()|processing-instruction()|text()"/> </xsl:template> <xsl:template match="xref"> <a> <xsl:attribute name="href"> <xsl:text>#</xsl:text><xsl:value-of select="@refid"/> </xsl:attribute> <xsl:choose> <xsl:when test="key('term-ids', @refid)[1]/@xreftext"> <xsl:value-of select="key('term-ids', @refid)[1]/@xreftext"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="key('term-ids', @refid)[1]"/> </xsl:otherwise> </xsl:choose> </a> </xsl:template> </xsl:stylesheet> Transforming the glossary with a targetLanguage of en gives these results: <html> <head> <META http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Glossary Listing: </title> </head> <body> <h1>Glossary Listing: </h1> <p> <b><a name="applet"></a>applet: </b> An application program, written in the Java programming language, that can be retrieved from a web server and executed by a web browser. A reference to an applet appears in the markup for a web page, in the same way that a reference to a graphics file appears; a browser retrieves an applet in the same way that it retrieves a graphics file. For security reasons, an applet's access rights are limited in two ways: the applet cannot access the filesystem of the client upon which it is executing, and the applet's communication across the network is limited to the server from which it was downloaded. Contrast with <a href="#servlet">servlet</a>. </p> <p> <b><a name="DMZlong"></a>demilitarized zone (DMZ): </b> In network security, a network that is isolated from, and serves as a neutral zone between, a trusted network (for example, a private intranet) and an untrusted network (for example, the Internet). One or more secure gateways usually control access to the DMZ from the trusted or the untrusted network. </p> <p> <b><a name="servlet"></a>servlet: </b> An application program, written in the Java programming language, that is executed on a web server. A reference to a servlet appears in the markup for a web page, in the same way that a reference to a graphics file appears. The web server executes the servlet and sends the results of the execution (if there are any) to the web browser. Contrast with <a href="#applet">applet</a>. </p> </body> </html> Figure C-5 shows how this document looks when it's rendered in a browser. Using a targetLanguage of jp gives us these results instead: Figure C-5. Generated HTML glossary<html> <head> <META http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Glossary Listing: </title> </head> <body> <h1>Glossary Listing: </h1> <p> <b><a name="DMZlong"></a>demilitarized zone (DMZ): </b> [Pretend this is a Japanese definition of DMZ.] </p> <p> <b><a name="servlet"></a>servlet: </b> [Pretend this is a Japanese definition of servlet.] </p> </body> </html> </programlisting> When rendered, the document looks like Figure C-6. Notice that we get entirely different results when we change the targetLanguage. Figure C-6. Generated HTML glossary
Synopsisboolean lang(string) InputsA 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. OutputIf the argument string is the same as, or is a sublanguage of, the context node's language, lang() returns the boolean value true. If the context node does not have an xml:lang attribute, then the value of the xml:lang attribute of its nearest ancestor is used instead. If there is no such attribute, then the lang() function returns the boolean value false. When comparing the language code of the context node with the argument string, the lang() function ignores case. Defined inXPath section 4.3, Boolean Functions. ExampleHere 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
Synopsisnumber last() InputsNone. OutputA number equal to the number of nodes in the current context. For example, if the current context contains 12 <li> nodes, last() returns 12. Defined inXPath section 4.1, Node Set Functions. ExampleWe'll use the last() function to handle the last item in a list in a special way. Here's the XML document we'll use: <?xml version="1.0"?> <list> <title>A few of my favorite albums</title> <listitem>A Love Supreme</listitem> <listitem>Beat Crazy</listitem> <listitem>Here Come the Warm Jets</listitem> <listitem>Kind of Blue</listitem> <listitem>London Calling</listitem> <listitem>Remain in Light</listitem> <listitem>The Joshua Tree</listitem> <listitem>The Indestructible Beat of Soweto</listitem> </list> Here is the stylesheet that handles the last <listitem> in the list differently: <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html"/> <xsl:template match="/"> <html> <head> <title> <xsl:value-of select="/list/title"/> </title> </head> <body> <h1> <xsl:value-of select="/list/title"/> </h1> <ul> <xsl:for-each select="/list/listitem"> <xsl:choose> <xsl:when test="position()=last()"> <li><b>Last, but not least: </b><xsl:value-of select="."/></li> </xsl:when> <xsl:otherwise> <li><xsl:value-of select="."/></li> </xsl:otherwise> </xsl:choose> </xsl:for-each> </ul> </body> </html> </xsl:template> </xsl:stylesheet> When we transform the XML document with this stylesheet, here are the results: <html> <head> <META http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>A few of my favorite albums</title> </head> <body> <h1>A few of my favorite albums</h1> <ul> <li>A Love Supreme</li> <li>Beat Crazy</li> <li>Here Come the Warm Jets</li> <li>Kind of Blue</li> <li>London Calling</li> <li>Remain in Light</li> <li>The Joshua Tree</li> <li> <b>Last, but not least: </b>The Indestructible Beat of Soweto</li> </ul> </body> </html> When rendered, the HTML file looks like Figure C-7. Figure C-7. Generated HTML document
Synopsisstring local-name(node-set?) InputsA 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. OutputA string corresponding to the local name of the first element in the argument node-set. If the node-set is empty, the local-name() function returns an empty string. Defined inXPath section 4.1, Node Set Functions. ExampleHere 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
Synopsisstring name(node-set?) InputsAn optional node-set. If no node-set is given, the name() function creates a node-set with the context node as its only member. OutputThe expanded name of the node. If the argument node-set is empty, or if the first node in the node-set does not have an expanded name, an empty string is returned. Defined inXPath section 4.1, Node Set Functions. ExampleHere 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
Synopsisstring namespace-uri(node-set?) InputsA 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. OutputThe namespace URI of the first node in the argument node-set. If the argument node-set is empty, the first node has no namespace URI, or the first node has a namespace URI that is null, an empty string is returned. Be aware that the namespace-uri() function returns an empty string for all nodes other than element and attribute nodes. Defined inXPath section 4.1, Node Set Functions. ExampleHere 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
Synopsisstring normalize-space(string?) InputsAn optional string. If the argument is omitted, the normalize-space() function uses the string value of the context node. OutputThe argument string, with whitespace removed as follows:
Defined inXPath section 4.2, String Functions. ExampleHere 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."
Synopsisboolean not(boolean) InputsA boolean value, or more commonly, an XPath expression that evaluates to a boolean value. Outputfalse if the input parameter is true; true if the input parameter is false. Defined inXPath section 4.3, Boolean Functions. ExampleTo 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.
Synopsisnumber number(object?) InputsAn object. The object is converted to a number as described in the following subsection. OutputA number. The object is converted to a number as follows:
Defined inXPath section 4.4, Number Functions. ExampleHere 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
Synopsisnumber position() InputsNone. OutputA number equal to the position of the current node in the evaluation context. Defined inXPath section 4.1, Node Set Functions. ExamplesThis example uses the position() function to determine the background color of the rows of a table. The background colors cycle through the options white, darkgray, and lightgreen. Here's the XML document we'll use: <?xml version="1.0"?> <list> <title>A few of my favorite albums</title> <listitem>A Love Supreme</listitem> <listitem>Beat Crazy</listitem> <listitem>Here Come the Warm Jets</listitem> <listitem>Kind of Blue</listitem> <listitem>London Calling</listitem> <listitem>Remain in Light</listitem> <listitem>The Joshua Tree</listitem> <listitem>The Indestructible Beat of Soweto</listitem> </list> We'll use this stylesheet to generate our HTML document: <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html"/> <xsl:template match="/"> <html> <head> <title> <xsl:value-of select="/list/title"/> </title> </head> <body> <h1> <xsl:value-of select="/list/title"/> </h1> <table border="1"> <xsl:for-each select="/list/listitem"> <xsl:variable name="background-color"> <xsl:choose> <xsl:when test="position() mod 3 = 1">white</xsl:when> <xsl:when test="position() mod 3 = 2">darkgray</xsl:when> <xsl:otherwise>lightgreen</xsl:otherwise> </xsl:choose> </xsl:variable> <tr bgcolor="{$background-color}"> <td> <b><xsl:value-of select="."/></b> </td> </tr> </xsl:for-each> </table> </body> </html> </xsl:template> </xsl:stylesheet> Our stylesheet generates the following results: <html> <head> <META http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>A few of my favorite albums</title> </head> <body> <h1>A few of my favorite albums</h1> <table border="1"> <tr bgcolor="white"> <td><b>A Love Supreme</b></td> </tr> <tr bgcolor="darkgray"> <td><b>Beat Crazy</b></td> </tr> <tr bgcolor="lightgreen"> <td><b>Here Come the Warm Jets</b></td> </tr> <tr bgcolor="white"> <td><b>Kind of Blue</b></td> </tr> <tr bgcolor="darkgray"> <td><b>London Calling</b></td> </tr> <tr bgcolor="lightgreen"> <td><b>Remain in Light</b></td> </tr> <tr bgcolor="white"> <td><b>The Joshua Tree</b></td> </tr> <tr bgcolor="darkgray"> <td><b>The Indestructible Beat of Soweto</b></td> </tr> </table> </body> </html> When rendered, the HTML file looks like Figure C-8. Figure C-8. HTML file displaying items with different background colors
Synopsisnumber round(number) DescriptionIf 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:
InputsA number. If the argument is not a number, it is converted to a number as if it were passed to the number() function. OutputThe integer that is closest to the argument. Special cases are handled as described in this section. Defined inXPath section 4.4, Number Functions. ExampleThe 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.
Synopsisboolean starts-with(stringstring) InputsTwo strings. OutputIf the first string begins with the second, starts-with() returns the boolean value true; otherwise it returns false. Defined inXPath section 4.2, String Functions. ExampleWe'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
Synopsisstring string(object) InputsAn object. The object is converted to a string, as described in the following subsection. OutputA string. The input argument is converted to a string as follows:
Defined inXPath section 4.2, String Functions. ExampleHere 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.
Synopsisnumber string-length(string?) InputsAn optional string. OutputThe number of characters defined in the string. Defined inXPath section 4.2, String Functions. ExampleThe 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.
Synopsisstring substring(stringnumbernumber?) InputsThe 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. OutputWith two arguments (a string and a starting position), the substring() function returns all characters in the string, starting with the starting position. Be aware that the first character in an XPath string is at position 1, not 0. With three arguments (a string, a starting position, and a length), the substring() function returns all characters in the string whose position is greater than or equal to the starting position and whose position is less than or equal to the starting position plus the length. Normally, the arguments to the substring() function are integers, although they may be more complicated expressions. See the "Example" section that follows for some unusual cases. Defined inXPath section 4.2, String Functions. ExampleWe'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.
Synopsisstring substring-after(stringstring) InputsTwo 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. OutputThe portion of the first argument that occurs after the first occurrence of the second argument. If the second argument does not appear in the first argument, the function returns an empty string. Defined inXPath section 4.2, String Functions. ExampleThis 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!
Synopsisstring substring-before(stringstring) InputsTwo 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. OutputThe portion of the first argument that occurs before the first occurrence of the second argument. If the second argument does not appear in the first argument, the function returns an empty string. Defined inXPath section 4.2, String Functions. ExampleThis 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!
Synopsisnumber sum(node-set) InputsA 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. OutputThe sum of the numeric values of all of the nodes in the argument node-set. If any node in the argument node-set cannot be converted to a number, the sum() function returns NaN. Defined inXPath section 4.4, Number Functions. ExampleWe'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
Synopsisobject system-property(string) DescriptionBy definition, all XSLT processors must support three system properties:
InputsThe 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. OutputThe value of the queried property. Defined inXSLT section 12.4, Miscellaneous Additional Functions. ExampleHere 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: Synopsismsxsl test1.xml systemproperties.xsl Here are the results: xsl:version = "1" xsl:vendor = "Microsoft" xsl:vendor-url = "http://www.microsoft.com"
Synopsisstring translate(stringstringstring) InputsThree strings. The first is the original, untranslated string, and the second and third strings define the characters to be converted. OutputThe original string, translated as follows:
Defined inXPath section 4.2, String Functions. ExampleHere'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
Synopsisboolean true() InputsNone. OutputThe boolean value true. Defined inXPath section 4.3, Boolean Functions. ExampleHere'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!
Synopsisstring unparsed-entity-uri(string) InputsThe name of the unparsed entity. OutputThe URI of the unparsed entity with the specified name. Defined inXSLT section 12.4, Miscellaneous Additional Functions. ExampleUnparsed 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. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|