Nodeset functions
String functions
Number functions
Boolean functions
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>
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.
The position() function returns the numeric position of the current element and has the following syntax:
number position()
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
You can use the last() function to return the final element of the current context. It has the following syntax:
number last()
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:
The first xsl:when uses position()=last() to return true if the current position equals the last position.
The second xsl:when tests for the second-to-last node.
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.
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>
You can use the count() function to get the total number of nodes in the current node set. Its syntax is:
number count(nodeset)
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
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])
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>
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.
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
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
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>
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) > 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.
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.
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
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
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.
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
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
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
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.
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.
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 |
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
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().
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>
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()
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)
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.
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.
Also see Chapter 10 for another example of using generate-id().
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:
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.
xsl:vendor returns a string that identifies the XSLT processor vendor.
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