Chapter 11

XPath Data Types and Functions

In This Chapter

bullet Nodeset functions

bullet String functions

bullet Number functions

bullet Boolean functions

bullet General purpose XSLT functions

T he very first words I could read as a child were free inside.

Everyone likes to get something for free, and with XSLT, you get a host of built-in functions for free inside XPath and XSLT. These functions give you a power boost that you can use when you create stylesheets.

Most of the built-in functions are categorized by the kind of data that they work with. The four primary data types in XSLT are: node sets, strings, numbers, and booleans. In this chapter, you find out all about the major built-in functions for these data types and about some general-purpose functions.

Throughout the chapter, I refer to the following menu.xml source document in Listing 11-1 to demonstrate the use of built-in functions.

Listing 11-1: menu.xml

<?xml version=”1.0”?>

<menu>

  <entree name=”Sunburnt Chicken”>

    <diet>false</diet>

    <fatgrams>23</fatgrams>

    <features>Salad, Vegetables, Baked Potato, and Dessert</features>

    <description>Chicken prepared so hot by our master chef Georgio Faucher, you’ll need a gallon of soda to wash it down. Bring sunscreen!</description>

  </entree>

  <entree name=”Filet Mig’s None”>

    <diet>true</diet>

    <fatgrams>0</fatgrams>

    <features>Soup, Vegetables, Baked Potato, and Dessert</features>

    <description>Our master chef Mig prepares a uniquely no-fat filet mignon. You won’t believe how great it tastes!</description>

  </entree>

  <entree name=”Chicken Parmashaun”>

    <diet>false</diet>

    <fatgrams>20</fatgrams>

    <features>Soup, Pasta, Baked Potato, and Dessert</features>

    <description>Our award-winning Chicken Parmesan prepared especially for you by our master chef Shaun.</description>

  </entree>

  <entree name=”Eggs Benelux”>

    <diet>false</diet>

    <fatgrams>35</fatgrams>

    <features>Bacon, Sausage, and Toast</features>

    <description>No matter the time of day, enjoy our scrumptous breakfast cooked by our famous Belgian and Dutch master chefs.</description>

  </entree>

  <entree name=”Jerk Chicken”>

    <diet>true</diet>

    <fatgrams>5</fatgrams>

    <features>Soup, Vegetables, and Dessert</features>

    <description>A delicious hot Jamaican dish prepared by our most obnoxious master chef.</description>

  </entree>

  <entree name=”Gusto Spaghetti”>

    <diet>false</diet>

    <fatgrams>55</fatgrams>

    <features>Soup, Salad, and Dessert</features>

    <description>Our famous master chef Boyd Ardee prepares a succulent dish of spaghetti with zesty gusto!</description>

  </entree>

</menu>

Playing ‘Heart and Soul’ with Nodes

Nodes are the heart and soul of an XSLT transformation, because ultimately, the result document is some sort of arrangement of nodes, whether they are elements, attributes, text, or whatever. Naturally, then, being able to add capabilities beyond what you can do with XSLT elements alone is important. Several functions are available for working with nodes.

Getting the current element’s position

The position() function returns the numeric position of the current element and has the following syntax:

number  position()

Tip

In this syntax, number describes the return data type (or type of data returned) by the position() function. I show return data types in italics throughout this chapter.

The position() function always returns a value based on the current context, which can sometimes be misleading. For example, take the following template rule:

  <xsl:template match=”entree”>

   <xsl:value-of select=”@name”/>’s position: <xsl:value-of select=”position()”/>

  </xsl:template>

When applied to the menu.xml document (see Listing 11-1), you might guess that the result document looks something like this:

Sunburnt Chicken’s position: 1

Filet Mig’s None’s position: 2

Chicken Parmashaun’s position: 3

Eggs Benelux’s position: 4

Jerk Chicken’s position: 5

Gusto Spaghetti’s position: 6

Logical guess, perhaps, but a wrong one. Although the stylesheet focuses on entree elements, don’t forget those hidden text nodes that appear between the element nodes. Look again at the source document, and this time I’ve removed the children of the entree elements for brevity:

  <entree name=”Sunburnt Chicken”></entree>

  <entree name=”Filet Mig’s None”></entree>

  <entree name=”Chicken Parmashaun”></entree>

  <entree name=”Eggs Benelux”></entree>

  <entree name=”Jerk Chicken”></entree>

  <entree name=”Gusto Spaghetti”></entree>

When the processor goes through the XML document, it finds the nodes in the following positions:

[text node: 1]

Sunburnt Chicken’s position: 2

[text node: 3]

Filet Mig’s None’s position: 4

[text node: 5]

Chicken Parmashaun’s position: 6

[text node: 7]

Eggs Benelux’s position: 8

[text node: 9]

Jerk Chicken’s position: 10

[text node: 11]

Gusto Spaghetti’s position: 12

The results that actually display in your result document are:

Sunburnt Chicken’s position: 2

Filet Mig’s None’s position: 4

Chicken Parmashaun’s position: 6

Eggs Benelux’s position: 8

Jerk Chicken’s position: 10

Gusto Spaghetti’s position: 12

Tip

If you find text nodes getting in the way of your position() logic, you can use the xsl:strip-space element to remove them prior to your template rule. See Chapter 13 for more information on xsl:strip-space.

Getting the last element

You can use the last() function to return the final element of the current context. It has the following syntax:

number  last()

Remember

The processor evaluates last() and all the other built-in functions when they are within an XPath expression, such as in the select attribute of the xsl:if or xsl:value-of instructions. You can’t just type functions inside the template apart from an XSLT instruction; if you do so, the processor treats the function as literal text and doesn’t evaluate it. As a general rule, remember that functions are defined only inside quotation marks. In fact, I think built-in functions could have their own Rawhide -like theme song: “Quote ’em, quote ’em, quote ’em. Though the streams are swollen, Keep them doggies rollin’, XSLT!”

I can use the position() and last() functions together in the following example to list out the entrees in a sentence-like format. Specifically, I want to create a list of the entree elements in which a comma is inserted between entrees, except for the second-to-last entree — it has an and, added instead. For the final entree, a period is added to close the sentence. The template rule containing this logic is shown here:

  <xsl:template match=”menu”>

    Tonight’s entrees are the following:

    <xsl:for-each select=”entree”>

      <xsl:value-of select=”@name”/>

      <xsl:choose>

        <xsl:when test=”position()=last()”>

        <xsl:text>.</xsl:text>

        </xsl:when>

        <xsl:when test=”position()=last()-1”>

          <xsl:text>, and </xsl:text>

        </xsl:when>

        <xsl:otherwise>

          <xsl:text>, </xsl:text>

        </xsl:otherwise>

      </xsl:choose>

    </xsl:for-each>

    <xsl:text>

    </xsl:text>

  </xsl:template>

The xsl:choose element tests for the following three conditions:

bullet The first xsl:when uses position()=last() to return true if the current position equals the last position.

bullet The second xsl:when tests for the second-to-last node.

bullet xsl:otherwise is used for the remaining nodes.

The formatted results are:

   Tonight’s entrees are the following: 

    Sunburnt Chicken, Filet Mig’s None, Chicken Parmashaun, Eggs Benelux, Jerk Chicken, and Gusto Spaghetti.

Returning the current node

You can return the current node to your code by using the current() function:

nodeset  current()

In the template rule that follows, the xsl:if instruction tests for an entree element that has a name attribute of Jerk Chicken. If so, then the xsl:copy-of instruction uses current() to copy the current node to the result tree:

  <xsl:template match=”entree”>

    <xsl:if test=”./@name=’Jerk Chicken’”>

      <xsl:copy-of select=”current()”/>

    </xsl:if>

  </xsl:template>

Tip

In this example, select=”current()” is functionally the same as select=”.”.

Getting the node set count

You can use the count() function to get the total number of nodes in the current node set. Its syntax is:

number  count(nodeset)

Tip

Anything that appears inside a function’s parenthesis is called an argument. The count() function, for example, has nodeset as a single argument.

The following template rule lists the total number of menu and entree nodes in the source document:

  <xsl:template match=”/”>

     menu nodes: <xsl:value-of select=”count(//menu)”/>

     entree nodes: <xsl:value-of select=”count(//entree)”/>

  </xsl:template>

The results are:

menu nodes: 1

entree nodes: 6

Getting a node name

When you add text to your result document, most of the time you are adding the content of the elements or perhaps the values of the attributes. About the only time you think of outputting the elements or attributes themselves is when you are creating an XML output. However, you may have occasions in which you want to treat the name of a node as text. If so, the name() function comes to the rescue, which returns a string value of the specified node’s name:

string  name([nodeset])

Tip

Any parameter that appears in brackets is optional. So, in the case of name(), the nodeset argument may or may not be defined. If it is not, then the current node is the nodeset being evaluated by the function.

In the template rule that follows, the name() function comes in handy in creating the header columns for an HTML table:

  <xsl:template match=”menu”>

    <table>

      <tr>

        <th><xsl:value-of select=”name( entree/@name )”/></th>

        <th><xsl:value-of select=”name( //diet )”/></th>

        <th><xsl:value-of select=”name( //fatgrams )”/></th>

        <th><xsl:value-of select=”name( //features )”/></th>

      </tr>

     <xsl:for-each select=”entree”>

       <tr>

         <td><xsl:value-of select=”@name”/></td>

         <td><xsl:value-of select=”diet”/></td>

         <td><xsl:value-of select=”fatgrams”/></td>

         <td><xsl:value-of select=”features”/></td>

       </tr>

     </xsl:for-each>

    </table>

  </xsl:template>

The resulting table is as follows:

<table>

   <tr>

      <th>name</th>

      <th>diet</th>

      <th>fatgrams</th>

      <th>features</th>

   </tr>

   <tr>

      <td>Sunburnt Chicken</td>

      <td>false</td>

      <td>23</td>

      <td>Salad, Vegetables, Baked Potato, and Dessert</td>

   </tr>

   <tr>

      <td>Filet Mig’s None</td>

      <td>true</td>

      <td>0</td>

      <td>Soup, Vegetables, Baked Potato, and Dessert</td>

   </tr>

   <tr>

      <td>Chicken Parmashaun</td>

      <td>false</td>

      <td>20</td>

      <td>Soup, Pasta, Baked Potato, and Dessert</td>

   </tr>

   <tr>

      <td>Eggs Benelux</td>

      <td>false</td>

      <td>35</td>

      <td>Bacon, Sausage, and Toast</td>

   </tr>

   <tr>

      <td>Jerk Chicken</td>

      <td>true</td>

      <td>5</td>

      <td>Soup, Vegetables, and Dessert</td>

   </tr>

   <tr>

      <td>Gusto Spaghetti</td>

      <td>false</td>

      <td>55</td>

      <td>Soup, Salad, and Dessert</td>

   </tr>

</table>

Working with Strings

So much of XSLT is based on pushing text from one place to another and transforming it along the way. Therefore, having functions that can manipulate and transform strings can be a valuable tool for you as an XSLT stylesheet author. This section covers the functions available for string manipulation.

Extracting strings from strings

XPath has three functions that help you extract a string from a larger string: substring-before(), substring-after(), and substring().

The syntax for the substring-before() and syntax-after() functions are:

string  substring-before(source, str) 

string  substring-after(source, str) 

substring-before() returns the portion of source that comes before the first occurrence of str. If str is not found, then the result is an empty string. On the other hand, the substring-after() function returns the portion of source that comes after the first occurrence of str. It too returns an empty string if str is not found in the source.

The following example uses substring-before() to test whether or not the features child element includes Soup before the first comma. If so, then text is added to the result document. The substring-after() function is used to list everything else that follows the Soup, string:

  <xsl:template match=”entree”>

    <xsl:if test=”substring-before( features, ‘,’) = ‘Soup’”>

      Soup is offered with <xsl:value-of select=”@name”/>

      Also offered are: <xsl:value-of select=”substring-after( features, ‘Soup,’)”/>

    </xsl:if>  

  </xsl:template>

The results are :

      Soup is offered with Filet Mig’s None

      Also offered are:  Vegetables, Baked Potato, and Dessert

  

      Soup is offered with Chicken Parmashaun

      Also offered are:  Pasta, Baked Potato, and Dessert

    

      Soup is offered with Jerk Chicken

      Also offered are:  Vegetables, and Dessert

  

      Soup is offered with Gusto Spaghetti

      Also offered are:  Salad, and Dessert

You use the substring() function to get a string buried inside another string. The function has the following syntax:

string  substring( source, start [, length] )

The substring() function returns the substring of source beginning at the start position and having a length of length. If length is not specified, then it returns the remainder of the string. The following example extracts a substring from each description, starting at the position 5 and returning 3 characters:

  <xsl:template match=”entree”>

    <xsl:value-of select=”substring( description, 5, 3 )”/>

  </xsl:template>

The result is:

  ken

  mas

  awa

  att

  lic

  fam

Searching and replacing text

You can use the translate() function to search and replace characters within a string. The syntax for the function is:

string  translate(source, searchstr, replacestr)

searchstr specifies a string of characters that the translate() function looks for inside source. When each character is encountered, the character at the same position in replacestr replaces the original character.

For example, suppose you want to change all the text of the entree name to uppercase. To do so, I can create two variables: lower contains an all lowercase alphabet, and upper contains uppercase characters of the alphabet. As an xsl:for-each instruction runs through each of the entrees, the translate() function is used to map all the lowercase characters in the entree’s name to the corresponding uppercase character:

  <xsl:variable name=”lower”>abcdefghijklmnopqrstuvwxzyz</xsl:variable>

  <xsl:variable name=”upper”>ABCDEFGHIJKLMNOPQRSTUVWXYZ</xsl:   variable>

  <xsl:template match=”menu”>

    <xsl:for-each select=”entree”>

      <xsl:value-of select=”translate( @name, $lower, $upper )”/><xsl:text>

      </xsl:text>

    </xsl:for-each>

  </xsl:template>

The result is shown here:

SUNBURNT CHICKEN

FILET MIG’S NONE

CHICKEN PARMASHAUN

EGGS BENELUX

JERK CHICKEN

GUSTO SPAGHETTI

Remember

Remember that the translate() function is used to search and replace individual characters, not strings.

Testing strings

You can test the contents of a string to check and see if another string is inside it with the contains() and starts-with() functions. The syntax for these functions is:

boolean  contains(source, str) 

boolean  starts-with(source, str) 

The contains() function returns true if str is found inside source. If not, then false is returned. starts-with() returns true if str is located at the start of the source string and false if not.

I use the contains() function in the following example to test for the presence of words in the entree’s name. Based on the result of these evaluations, I add the entree into the appropriate category name:

  <xsl:template match=”entree”>

    <entree>

      <name><xsl:value-of select=”@name”/></name>

      <category>

      <xsl:choose>

        <xsl:when test=”contains( @name, ‘Chicken’ )”>Chicken</xsl:when>

        <xsl:when test=”contains( @name, ‘Spaghetti’ )”>Italiano</xsl:when>

        <xsl:when test=”contains( @name, ‘Filet’ )”>Beef</xsl:when>

        <xsl:otherwise>Other</xsl:otherwise>

      </xsl:choose>

      </category>

    </entree>

  </xsl:template>

The results follow:

  <entree>

    <name>Sunburnt Chicken</name>

    <category>Chicken</category>

  </entree>

  <entree>

    <name>Filet Mig’s None</name>

    <category>Beef</category>

  </entree>

  <entree>

    <name>Chicken Parmashaun</name>

    <category>Chicken</category>

  </entree>

  <entree>

    <name>Eggs Benelux</name>

    <category>Other</category>

  </entree>

  <entree>

    <name>Jerk Chicken</name>

    <category>Chicken</category>

  </entree>

  <entree>

    <name>Gusto Spaghetti</name>

    <category>Italiano</category>

  </entree>

Getting the length of a string

The string-length() function returns just what you’d expect from a name like that: the length of a string. It looks like:

number  string-length([string]) 

The example that follows uses string-length() to evaluate the size of the description element. If it is over 90 characters in length, it is flagged in the result document as being too long:

  <xsl:template match=”entree”>

    ==============================================

    <xsl:value-of select=”@name”/>’s description:

    ==============================================

    “<xsl:value-of select=”description”/><xsl:text>”

    </xsl:text>

    <xsl:if test=”string-length(description) &gt; 90”>

    **** Hey there, Tex, this description is too long (<xsl:value-of select=”string-length(description)”/> chars). Please shorten. ***

    </xsl:if>

   </xsl:template>

When the menu.xml (refer to Listing 11-1) is applied using this template rule, the output is:

    ==============================================

    Sunburnt Chicken’s description:

    ==============================================

    “Chicken prepared so hot by our master chef Georgio Faucher, you’ll need a gallon of soda to wash it down. Bring sunscreen!”

    

  

    ==============================================

    Filet Mig’s None’s description:

    ==============================================

    “Our master chef Mig prepares a uniquely no-fat filet mignon. You won’t believe how great it tastes!”

    

    **** Hey there, Tex, this description is too long (99 chars). Please shorten. ***

    

  

    ==============================================

    Chicken Parmashaun’s description:

    ==============================================

    “Our award-winning Chicken Parmesan prepared especially for you by our master chef Shaun.”

    

  

    ==============================================

    Eggs Benelux’s description:

    ==============================================

    “No matter the time of day, enjoy our scrumptious breakfast cooked by our famous Belgian and Dutch master chefs.”

    

    **** Hey there, Tex, this description is too long (110 chars). Please shorten. ***

    

  

    ==============================================

    Jerk Chicken’s description:

    ==============================================

    “A delicious hot Jamaican dish prepared by our most obnoxious master chef.”

    

  

    ==============================================

    Gusto Spaghetti’s description:

    ==============================================

    “Our famous master chef Boyd Ardee prepares a succulent dish of spaghetti with zesty gusto!”

In this example, two of the descriptions had a string length of over 90 characters and were flagged.

Concatenating a string

To combine several smaller strings into a whopping big string, you can use the concat() function:

string  concat(string1, string2, [string3,...]) 

This function combines string1 with string2 and as many other strings as you wish and returns them as a single concatenated string.

I use the concat() function in the following template rule to assemble a sentence out of literal text, an attribute value, and the string value of an element:

  <xsl:template match=”entree”>

    <xsl:value-of select=”concat( ‘The ‘, @name, ‘ entree has ‘, fatgrams, ‘ grams of fat.’)”/>

   </xsl:template>

The result is:

  The Sunburnt Chicken entree has 23 grams of fat.

  The Filet Mig’s None entree has 0 grams of fat.

  The Chicken Parmashaun entree has 20 grams of fat.

  The Eggs Benelux entree has 35 grams of fat.

  The Jerk Chicken entree has 5 grams of fat.

  The Gusto Spaghetti entree has 55 grams of fat.

Trimming whitespace from strings

When you work with strings, you may frequently come across a situation in which whitespace is padded onto the beginning or end of a string you are using. The normalize-space() function is used to remove these unwanted whitespace areas in your string:

string  normalize-space([string])

The returned string has been stripped of leading and trailing whitespace as well as replacing multiple whitespace characters with a single whitespace character inside of the string.

To demonstrate, the normalize-space() function is useful to clean up the substring-after() example earlier in the chapter. Note the extra whitespace in the following section from its result document (before Vegetables):

      Soup is offered with Filet Mig’s None

      Also offered are:  Vegetables, Baked Potato, and Dessert

Putting a normalize-space() inside that template helps clean up the result by removing this extra space:

  <xsl:template match=”entree”>

    <xsl:if test=”substring-before( features, ‘,’) = ‘Soup’”>

      Soup is offered with <xsl:value-of select=”@name”/>

      Also offered are: <xsl:value-of select=”normalize-space(substring-after( features, ‘Soup,’))”/>

    </xsl:if>  

  </xsl:template>

The trimmed results are:

      Soup is offered with Filet Mig’s None

      Also offered are: Vegetables, Baked Potato, and Dessert

  

      Soup is offered with Chicken Parmashaun

      Also offered are: Pasta, Baked Potato, and Dessert

    

      Soup is offered with Jerk Chicken

      Also offered are: Vegetables, and Dessert

  

      Soup is offered with Gusto Spaghetti

      Also offered are: Salad, and Dessert

Converting an object into a string

To convert a node, number, or boolean value to a string, use the string() function:

string  string(object) 

A boolean value of false is converted to the string ‘false’, while true becomes ‘true’. A number becomes a string representation of the numeric value. A node returns its string value, while a nodeset returns the string value of the first node.

For example, the following boolean value

He answered: <xsl:value-of select=”string( false() )”/>

Becomes:

He answered: false

Numerically Speaking

Although XSLT wasn’t designed for number crunching, you can use it to do some basic manipulation of numbers. Check out the following built-in functions.

Converting an object into a number

You can use the number() function to convert the specified object into a number. If the object is a string, then it is converted to the nearest numeric value specified by the string. A boolean value of false is converted to 0, while true returns a 1. A node is first converted to a string value and then is converted as a string. The function’s syntax is:

number  number([object])

The following snippet of XSLT converts a string to a number for calculation:

<xsl:value-of select=”3.34*number(‘4.5’)”/>

Results in:

15.03

Rounding numbers

You can round numbers to the nearest integer number with the round() function:

number  round(number) 

By applying round() to the example in the preceding section:

<xsl:value-of select=”round( 3.34*number(‘4.5’) )”/>

I get a rounded integer value:

15 

Getting highest and lowest integer values

You can obtain the highest and lowest integer values by using the floor() and ceiling() functions:

number  floor(number) 

number  ceiling(number) 

When called, floor() evaluates the specified number value and returns the lowest integer number that is not less than the value. The ceiling() function does the converse — returning the highest integer number that is not greater than the value. To see how this works, take a look at the following code snippet:

Floor: <xsl:value-of select=”floor( 3230.20 )”/>

Ceiling: <xsl:value-of select=”ceiling( 3230.20 )”/>

The results look like this:

Floor: 3230

Ceiling: 3231

Summing it all up

The sum() function allows you to get the sum of the number values of the nodes in the specified nodeset:

number  sum(nodeset) 

In other words, sum() first converts each node in the nodeset to a number and then tallies up the numbers.

The following template rule uses sum() to add up the numeric values for all the fatgrams elements in the source tree:

  <xsl:template match=”/”>

  If you eat all of our entrees, you will eat a total of <xsl:value-of select=”sum( //fatgrams )”/> grams of fat.

  </xsl:template>

The following sentence results from the transformation:

If you eat all of our entrees, you will eat a total of 138 grams of fat.

Formatting a number

When numbers are displayed as strings, you’ll often want to format them in a specific manner. The format-number() function allows you to take a number and obtain a string version of it in the format you specify. Its syntax is:

string  format-number(number, formatstring [, decimalformat]) 

When processed, the number argument is converted to a string and is formatted based on formatstring. Table 11-1 shows the symbols you can use to compose the formatstring value.

Table 11-1 formatstring Symbols
Symbol Means Example (using 1,000 as the
number to be formatted)
0 Any numeric digit With 00000, 1,000 would display as 01000
# A digit with zero With #####, 1,000 would display as 1000
showing as absent
. A decimal point in a number With #####.00, 1,000 would display as 1000.00
, A thousands grouping symbol With #,####, 1,000 would display as 1,000
- Default negative prefix With -####, 1,000 would display as -1,000
% Multiply by 100 and With ####%, 1,000 would display as 100000%
show as percentage
$ U.S. currency sign (replaced With $####, 1,000 would display as $1000
by appropriate currency symbol)
X Any other characters can be With ABC-####, 1,000 would display as
used in the prefix or suffix ABC-1000
TechnicalStuff

The formatstring argument is based on the DecimalFormat class of Java 1.1. For full details, go to java.sun.com/products/jdk/1.1/docs/api/java.text.DecimalFormat.html.

The following template rule shows how the format-number() function can output a variety of numeric formats based on the formatstring argument:

  <xsl:template match=”/”>

    <xsl:variable name=”constant” select=”00433339.03”/>

    <xsl:value-of select=”format-number( $constant, ‘#’ )”/><xsl:text>

    </xsl:text>

    <xsl:value-of select=”format-number( $constant, ‘00000000000’ )”/><xsl:text>

    </xsl:text>

    <xsl:value-of select=”format-number( $constant, ‘#,###’ )”/><xsl:text>

    </xsl:text>

    <xsl:value-of select=”format-number( $constant, ‘#.##’ )”/><xsl:text>

    </xsl:text>

   <xsl:value-of select=”format-number( $constant, ‘$#,###,###.##’ )”/><xsl:text>

    </xsl:text>

   <xsl:value-of select=”format-number( $constant, ‘#%’ )”/><xsl:text>

    </xsl:text>

   <xsl:value-of select=”format-number( $constant, ‘SE-#-EP’ )”/><xsl:text>

    </xsl:text>

  </xsl:template>

The results are shown below:

433339

00000433339

433,339

433339.03

$433,339.03

43333903%

SE-433339-EP

Booleans: To Be or Not to Be

The final major data type XSLT deals with is boolean, which is a simple binary state (true or false). The four built-in functions for boolean values are: not(), true(), false(), and boolean().

Returning the opposite value

To return a value that’s opposite from the one you have, you can use the not() function:

boolean  not(boolean) 

The following xsl:if instruction evaluates to true if the myvar variable is not true:

<xsl:if test=”not( $myvar )”>

  This was not true.

</xsl:if> 

Returning true and false values

To return a true value (no, not the hardware store), use the true() function:

boolean  true()

To return a false value, use the false() function:

boolean  false() 

Converting to a boolean

You can convert a value to a boolean with the boolean() function. A string and node returns true when it is not empty, whereas a number is true if it is not equal to 0. The syntax is:

boolean  boolean(object) 

General Purpose Functions

In addition to the built-in functions centered around data types, XSLT adds some general purpose functions for specific uses. I discuss these functions in this section.

Generating a unique ID string

You can generate a unique identifier for a node using generate-id(). This becomes useful when you need a unique value for each element in the result document. The XSLT processor generates the identifier during the transformation; the value of the identifier consists of any string of alphabetical or numeric characters, but it must start with an alphabetic character. The syntax for the function is:

   string  generate-id([nodeset]) 

The following example uses generate-id() to assign a value to a new id attribute and declare a new element:

  <xsl:template match=”entree”>

    <entree id=”{generate-id()}” name=”{@name}”><xsl:text>

    </xsl:text><xsl:element name=”{generate-id()}”/><xsl:text>

  </xsl:text></entree>

  </xsl:template>

The results are:

  <entree id=”d0e3” name=”Sunburnt Chicken”>

    <d0e3/>

  </entree>

  <entree id=”d0e18” name=”Filet Mig’s None”>

    <d0e18/>

  </entree>

  <entree id=”d0e33” name=”Chicken Parmashaun”>

    <d0e33/>

  </entree>

  <entree id=”d0e48” name=”Eggs Benelux”>

    <d0e48/>

  </entree>

  <entree id=”d0e63” name=”Jerk Chicken”>

    <d0e63/>

  </entree>

  <entree id=”d0e78” name=”Gusto Spaghetti”>

    <d0e78/>

  </entree>

Pay special attention to the fact that, even though generate-id() is used twice in the template rule, the same ID value is generated for each of these times in each entree particular element node. The reason is that generate-id() creates a unique ID for a context node, so as long as the node stays in context, then the same value is returned.

Tip

If you run this code more than once, you’ll likely get a different set of identifier values each time you run it, because the IDs are generated to be unique for a particular transformation. In fact, if you apply the same stylesheet twice, you will likely get different IDs both times. The important part is not the specific values themselves, but that they are unique within that particular transformation.

Also see Chapter 10 for another example of using generate-id().

Returning system information

You can use the system-property() function to obtain certain system-level information, usually about the processor itself:

   object  system-property(string) 

Each processor is required to support a minimum of three properties:

bullet xsl:version returns a number indicating the version of XSLT that the processor implements. For example, for XSLT processors implementing XSLT 1.0, the number 1.0 is returned.

bullet xsl:vendor returns a string that identifies the XSLT processor vendor.

bullet xsl:vendor-url returns a string declaring a URL for the vendor of the XSLT processor.

The following stylesheet prints these three properties:

  <xsl:template match=”/”>

 XSLT Version Supported: <xsl:value-of select=”system-property( ‘xsl:version’ )”/><xsl:text>

 </xsl:text>

 XSLT Processor: <xsl:value-of select=”system-property( ‘xsl:vendor’ )”/><xsl:text>

 </xsl:text>

 For More Info: <xsl:value-of select=”system-property( ‘xsl:vendor-url’ )”/><xsl:text>

 </xsl:text>

</xsl:template>

When run against the SAXON 6.4 processor, the following results are generated:

 XSLT Version Supported: 1

 XSLT Processor: SAXON 6.4.4 from Michael Kay

 For More Info: http://saxon.sourceforge.net

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.224.62.105