Chapter 11. XSLT Functions and Related XSLT Elements

CONTENTS
  •  11.1 XSLT Function Groups
  •  11.2 String XSLT Functions
  •  11.3 The Boolean XSLT Function Group
  • current(), document(), element-available(), format-number(), function-available(), generate-id(), key(), system-property(), unparsed-entity-uri()

  • <xsl:key>

  • <xsl:decimal-format>

The versatility of XSLT is greatly enhanced by the range of XPath functions (described in Chapter 5), which provide the ability to perform many sophisticated tasks. XSLT provides its own library of functions, specific to XSLT implementations, in addition to the core XPath library of functions. These XSLT functions are used within expressions and are declared by the XSLT specification in the same manner as XPath functions, using a function prototype, as shown in the following structure:

Function: return type name(arguments) 

This chapter will discuss the nine XSLT functions, which are summarized in Table 11-1, as well as the two XSLT elements <xsl:key> and <xsl:decimal-format> and their relationships to the key() and format-number() functions, respectively. The reference number in the last column provides a quick lookup for the section of this chapter specifically applicable to a given function.

Table 11-1. XSLT functions
Function Name XSLT Function Group Returns Arguments Argument Type Ref.
current() Node-set Node-set None None 11.1.2
document() Node-set Node-set Object Node-set Required Optional 11.1.1.1
element-available() Boolean Boolean String Required 11.3.1
format-number() String String Number String String Required Required Optional 11.2.3
function-available() Boolean Boolean String Required 11.3.2
generate-id() String String Node-set Optional 11.2.2
key() Node-set Node-set String Object Required Required 11.1.3
system-property() String Object String Required 11.2.1
unparsed-entity-uri() String String String Required 11.2.4

11.1 XSLT Function Groups

XSLT function groups follow the same conventions as XPath core function groups. There are four XPath function groups aligned with the four objects they produce: node-set, string, Boolean, and number. However, there are no XSLT functions in the number function group, so there is technically no XSLT number function group.

The XSLT functions that return node-sets are: document(), which works with material from external documents; key(), which provides an index-like addressing capability; and current(), which provides a way to explicitly address the current node in a given context. These three functions are in the node-set XSLT function group.

The XSLT functions that return strings are: system-property(), which is used to access information about the XSLT processor that is processing the stylesheet; format-number(), which is used to set specific parameters for the formatting of a number; generate-id(), which is used to create IDs for nodes, and unparsed-entity-uri(), which is used to return the value of entities. These four functions are in the string XSLT function group.

The XST functions that return a Boolean value are: element-available(), which checks to see if a particular element is supported by the processor being used; and function-available(), which checks to see if a particular function is supported in the processor being used. These two functions are in the Boolean XSLT function group.

11.1.1 Node-set XSLT Functions

The XSLT node-set function group augments the basic set of XPath node-set functions with the addition of a document() function for importing XML data from more than one source instance, a current() function for making explicit the current node regardless of the context node and the key() function, which, together with the <xsl:key> element, provide an index-like functionality for "looking up," or referencing, elements.

11.1.1.1 The document() XSLT Function

The document() XSLT function enables input for the XSLT stylesheet to come from more than one XML document instance source. By using document(), you can add the contents of an external XML document to the basic input source tree. The document() XSLT function is defined using the following function prototype:

Function: node-set document (object, node-set?)
Function Name Function Group Function Return Type Arguments Argument Type
document() Node-set Node-set Object Node-set Required Optional

The document() function returns a node-set containing the root node of the document that is retrieved by the processor. The node-set returned by the document() function can be additionally qualified using a fragment identifier. Fragment identifiers select particular nodes in or descendants of the node-set. Fragment identifiers and their use are discussed in Section 11.1.1.3.

The first required argument of the document() function can be any object type, but if it is not a node-set, its value is converted to a string, which is interpreted as a URI. When the first argument is a node-set, each node in the node-set is evaluated and converted to a string. The strings resuting from each node in the node-set are then treated as if from individual calls by the document() function, resulting in a URI for each node.

The second argument is an optional node-set, and is used to identify an alternative base URI for the resolution of a relative URI in the first argument into an absolute URI.

11.1.1.2 Absolute, Relative, and Base URIs

The URI defined by the node-set in the second argument for the document() function can be either absolute or relative.

Absolute URIs can be in the form of an explicit URL, such as http://www.my_node-set.org/seminar.xml, or an explicit location path on a file system, such as c:\mydocs\seminar.xml.

Relative URIs are in the form of a URI or filename that is not explicitly pathed, such as seminar.xml. Relative URIs have a base URI, which is the default path or URL that will convert the relative path to an absolute path. Base URIs default to the base location in which the XSLT process is occurring.

A base URI is an absolute URI that can be used to convert a relative URI into an absolute URI. Concatenating a base URI and a relative URI will result in an absolute URI.

11.1.1.3 Fragment Identifiers

A fragment identifier in XSLT is used to select a subset of the nodes in the document that is returned by the document() function. This allows the selection of a child element in the document rather than the document element as the value returned by the document() function. If the resolved URI does not contain a node-set qualifier, the root node of the document is used as the node-set result. For example, adding "//test" to the end of the document() function as shown below changes the node-set returned by the document() function to the <test> element instead of the <seminar> element (assuming seminar.xml contains a <seminar> element that has a descendant called <test>).

document('seminar.xml')//test 

Note

Fragment identifiers are defined in RFC2396* Uniform Resource Identifiers (URI): Generic Syntax, Section 4.1. The normal syntax for a fragment identifier is to add the path of the identifier at the end of the URI, separated from the URI by a hash (#). The RFC (Request For Comments) allows implementations to interpret and format the fragment identifiers according to media type. The implementation of fragment identifiers by XSLT processors is media type-specific, according to the media type of the resulting object retrieved by the URI. In relation to the document() function, fragment identifiers do not use the # symbol because the function returns a node-set. Selecting nodes in a node-set is accomplished using location paths, defined in the XPath specification. This means that a fragment identifier in XSLT must use an XPath pattern to select a subset of nodes.

*See http://www.w3.org/TR/xpath#RFC2396.

11.1.1.4 The document() Function with a Non-Node-set First Argument

The first required argument of the document() function can be any object type, but if it is not a node-set, its value is converted to a string, which is interpreted as a URI. XSLT processors are not constrained to support any particular kind of URI, though most will resolve URLs. If the first argument to document() results in a URI of a type not supported by the XSLT processor, the processor can either report the error or just return an empty node-set.

The W3C specification implicitly requires that the document identified by a URI in the first argument to document() be a well-formed XML document. The document could take the form, for instance, of an XML-compliant HTML page one that was well-formed, at least or an XHTML page. However, if the document pointed to is not well-formed XML, the XSLT processor will either return an error or an empty node-set.

Suppose Markup City is to be augmented along the <boulevard> by the National Parks Service, and there is an online plan for a new park off of Old Chimney Road. With government funding being such a fickle process, the information on what the National Parks Service is planning will change regularly, so we might just want to get all the text information about the plan in its most up-to-date form from the government's Web site (http://www.national_parks_service.gov) each time we meet to discuss the new park. The information for the new <park> is located in a file called monte_sano.xml on their site. Example 11-1 shows the input file, the main stylesheet, the monte_sano.xml file and the stylesheet used to import it, as well as the result of the processing of the stylesheet.

In this example, we use an LRE to add a <park> element, and <park> is populated with the text contents of the monte_sano.xml file, retrieved by the document() function using the <xsl:value-of> instruction. Notice that the filename is in single quotes to specify that the first argument of the document() function is a string. The <block> LRE and <xsl:apply-templates> assure us that Old Chimney Road is still output as a named block.

Example 11-1 Using the XSLT document() function.
INPUT 1: <?xml version="1.0"?> <boulevard>              <block>Panorama Street</block>              <block>Highland Plaza</block>              <block>Hutchens Avenue</block>              <block>Wildwood Drive</block>              <block>Old Chimney Road</block>              <block>Carrol Circle</block> </boulevard> STYLESHEET: <?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"                  version="1.0"> <xsl:output indent="yes"/> <xsl:strip-space elements="*"/> <xsl:template match="block"> <block> <xsl:apply-templates/> </block> </xsl:template> <xsl:template match="boulevard/block[contains(., 'Old Chimney')]"> <park> <xsl:value-of select="document('http:// www.national_parks_service.gov/monte_sano.xml')" /> </park> <block> <xsl:apply-templates/> </block> </xsl:template> </xsl:stylesheet> INPUT 2: monte_sano.xml: <?xml version="1.0"?> <park><name>Century Park</name> </park> RESULT: <?xml version="1.0" encoding="utf-8"?> <block>Panorama Street</block> <block>Highland Plaza</block> <block>Hutchens Avenue</block> <block>Wildwood Drive</block> <park>Century Park</park> <block>Old Chimney Road</block> <block>Carrol Circle</block> 

Note

Use <xsl:value-of select="document ('monte_sano.xml')" /> (without the Web site reference) to access the contents of a file on the file system in the same directory as the stylesheet.

Working with <xsl:value-of> does not allow us to do much more processing with the elements in the file returned from the string URI. We could, however, access elements and attributes of the monte_sano.xml file by using the XSLT <xsl:apply-templates> instruction element, as shown below.

<xsl:apply-templates select= "document('http://www.national_parks_service.gov/monte_sano.xml')" /> 

Now, since the contents of the monte_sano.xml file are available as child nodes, we can add template rules for the elements in the external file to restructure the new park according to the file's XML contents, as shown in Example 11-2.

In this example, each element in the second input document, called with the document() function, is addressed with a template rule. The template rule with a match on "park" uses an LRE to generate the <park> tags. Then it uses <xsl:apply-templates> to continue processing the contents of the <park>. The template rule that matches on "park//*[@*]" is matching each element that is a decendant of <park>, but only if it has an attribute specified. The attribute may have any name, designated with the @* symbol. Elements without attributes are not matched, so they are handled by the built-in template rules (discussed in Chapter 3). The <name> element is matched and copied to the output using the <xsl:copy>, and the text is sent through to the output result tree because of the built-in template rule for text nodes.

Example 11-2 Adding a park with document().
INPUT 1: <?xml version="1.0"?> <boulevard>              <block>Panorama Street</block>              <block>Highland Plaza</block>              <block>Hutchens Avenue</block>              <block>Wildwood Drive</block>              <block>Old Chimney Road</block>              <block>Carrol Circle</block> </boulevard> INPUT 2: monte_sano.xml: <?xml version="1.0"?> <park><name>Century Park</name> <facilities> <pavilion quantity="10"/> <restrooms quantity="20"/> <playgrounds quantity="5"/> <ballfield quantity="8"/> </facilities> <grounds> <landscape/> <sprinklers layout="3700"/> <topography designation="6313"/> <lighting/> </grounds> </park> STYLESHEET: <?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"                  version="1.0"> <xsl:output indent="yes"/> <xsl:strip-space elements="*"/> <xsl:template match="boulevard/block[contains(., 'Old Chimney')]"> <xsl:apply-templates select="document('http:// www.national_parks_service.gov/monte_sano.xml')" /> <block> <xsl:apply-templates /> </block> </xsl:template> <xsl:template match="block"> <xsl:copy> <xsl:apply-templates/> </xsl:copy> </xsl:template> <xsl:template match="park"> <park> <xsl:apply-templates/> </park> </xsl:template> <xsl:template match="park//*[@*]"> <xsl:copy> <xsl:value-of select="@*"/> <xsl:apply-templates/> </xsl:copy> </xsl:template> <xsl:template match="park/name"> <xsl:copy> <xsl:value-of select="."/> </xsl:copy> </xsl:template> </xsl:stylesheet> RESULTS: <?xml version="1.0" encoding="utf-8"?> <block>Panorama Street</block> <block>Highland Plaza</block> <block>Hutchens Avenue</block> <block>Wildwood Drive</block> <park> <name>Century Park</name> <pavilion>10</pavilion> <restrooms>20</restrooms> <playgrounds>5</playgrounds> <ballfield>8</ballfield> <sprinklers>3700</sprinklers> <topography>6313</topography> </park> <block>Old Chimney Road</block> <block>Carrol Circle</block> 
11.1.1.5 Using document() to Reference the XSLT Stylesheet

The content of the XSLT stylesheet itself can be referenced using a pair of whitespace-separated quotes, document(' '). This will return the root node of the XSLT stylesheet that contains the document() function call.

This use of the first argument to document() is analogous to the notation for "self" with "." when referring to nodes. In other words, this space says, "Look in this stylesheet being processed right now." This is not affected by the fact that the document() function might be called from an included or imported set of template rules with the use of <xsl:import> and <xsl:include>. In that case, the local stylesheet is still the one in which the imported or included template rule is instantiated, not the one from which it was imported or included.

11.1.1.6 The document() Function with a Node-set First Argument

The first argument of the document() function can contain an expression, which can be used to generate the URI. For example, you could select an attribute node from the input document, which might contain the URI for the document to import. The document() function would then resolve the content of each node in the node-set to a string, resulting in a URI for each node. If there is more than one node in the node-set, each node is processed into a URI and each URI is resolved into a document that is used as input to the process. This way, more than one document can be included with one document() function.

Perhaps MarkupCity.xml contains another section called <city_plans>, with a section of <online> references to a government Web site containing comprehensive, up-to-date (at least by government standards) copies of the city plans as follows:

<city_plans><online href="monte_sano.xml"/></city_plans> 

We would use an expression in the document() function to select the attribute node "href" and get its contents as follows:

document(//city_plans/online/@href) 

Note that we do not use single quotes to designate the argument as a string. An argument without quotes as shown here is processed as an expression. This use of the document() function will access the document pointed to by the URI in the href attribute of any <online> element found, if it is a child of <city_plans>. For example, the XML input document might contain several <online> element children of the <city_plans> element, as shown below.

<city_plans> <online href="http://www.local.gov/plans/parks.xml" />       <online href="http://www.local.gov/plans/roads.xml" />       <online href="http://www.local.gov/plans/recycle.xml" /> </city_plans> 

Each of these href attributes would be resolved, and all three external documents would be returned from their URIs.

11.1.1.7 Using document() with Two Node-set Arguments

The second argument to the document() function, when used, provides the context for the URI in the first argument. This basically means that, if the URI in the first argument is a relative URI, the second argument can be used to resolve the relative URI into an absolute URI. A relative URI is resolved into an absolute URI by adding the base URI during processing. The processor uses several criteria to determine the base URI as follows:

  1. If there is only one argument to the document() function and the URI resulting from that argument is a relative URI, the base URI comes from the element in the stylesheet that contains the document() function.

    1. If the element in the stylesheet comes from an included or imported stylesheet in another location, that location is used as the base URI for the relative URI.

    2. The default base URI is the location of the stylesheet.

  2. If there are two arguments to the document() function, the base URI of the node-set in the second argument is used as the base URI for the relative URI in the first argument.

  3. If the first argument is an absolute URI, the second argument is ignored.

Basically, when the second argument is added, the effect is generally only noticed when a relative URI is used. The second argument can then qualify the location, which will be the base URI for the first argument. Think of the second argument as a way of saying, "Look over there, instead." A simple example would be to use a relative path to the monte_sano.xml file as shown here:

document('monte_sano.xml') 

Without the second argument, the processor would look in the same directory as the stylesheet that contains the element calling the document() function. Adding a second argument, we could redirect the processor to look in another directory, based on the location of that node-set. This is especially helpful for elements that may be located in a different directory and reference using entities.

document('monte_sano.xml', city_plan) 

By adding the city_plan second argument, the processor would look for an element in the input file called city_plan and use the absolute location of that element for the base URI of the monte_sano.xml file.

11.1.2 The current() XSLT Function

The current() XSLT function is used to get the current node that is being processed, regardless of where the function is being called. It takes no arguments, and its function return type is a node-set, as shown in the following function prototype:

Function: node-set current()
Function Name Function Group Function Return Type Arguments Argument Type
current() Node-set Node-set None None

When a template match is found by the XSLT processor and the given template rule is instantiated, each node in the node-set returned by that match is both the current node and the context for that template rule. However, expressions in the instruction elements within the template can change the context node when they are instantiated. Using the current() function in an instruction element expression returns the original node that was matched by the template rule.

The following examples, derived from the XSLT W3C specification, serve to clarify the distinction between the current node and the context node. The following two expressions for <xsl:apply-templates> are equivalent for an expression that is not contained in another expression:

<xsl:apply-templates select="current()" /> <xsl:apply-templates select="." /> 

However, when a predicate is used, the context node changes from subexpression to subexpression. The current() function, then, reaches outside the square brackets, as it were, to reference the original current node of the template that contains the expression. Again, the specification provides a good example:

<xsl:apply-templates select="//glossary/item[@name=./@ref]" /> 

This is looking for the name and ref attributes to have the same value that is, name and ref attributes of the item element. For that matter, then, you could also phrase this as the following:

<xsl:apply-templates select="//glossary/item[./@name=./ @ref]" /> 

which means the same thing. Accordingly, then, the redundancy here is underscored by:

<xsl:apply-templates select="//glossary/item[@name=@ref]" /> 

In all three cases, we are looking for item elements that are children of glossary elements, which have name and ref attributes whose values are equal. Now, notice the contrast when we use current():

<xsl:apply-templates select="//glossary/item[@name=current()/@ref]" /> 

Here, current() is reaching outside the brackets. The node referenced by current() is the original context node of the template. As contradictory as it may sound, even though the current node and context nodes are often two different things, the current() function references the template's context node when used in a predicate. This is because at the level where the template is matched, the context node and the current node are the same node. By invoking current(), we are asking for any ref attributes of the original node that were matched with the match attribute of <xsl:template>. At the point in the predicate where the expression occurs, the context node is the item element in a glossary element.

11.1.3 The key() XSLT Function and the <xsl:key> Top-Level Element

The key() XSLT function is used to retrieve the value of a key that was previously defined using the <xsl:key> top-level element. Since keys need to be defined before they can be used, we will discuss the <xsl:key> element first.

11.1.3.1 The <xsl:key> Top-level Element

The <xsl:key> top-level element is used to associate a key with a node from the input XML document. Each key associated with a node also has a value defined with <xsl:key>. Getting and using the values of the keys defined with <xsl:key> involves the key() function, which is described in Section 11.1.3.2. The <xsl:key> element is an empty element that uses three required attributes, as shown in the following element model definition:

<!-- Category: top-level-element --> <xsl:key   name = qname   match = pattern   use = expression /> 

The <xsl:key> element uses the name attribute to create the name of a key. The match attribute's pattern is used to define the node to which the key will apply. The use attribute is an expression that defines the information to be used to apply a value to the key. These attributes are discussed in the following sections.

The <xsl:key> name Attribute

The required name attribute denotes the name by which the key will be referenced. This name is also used as the string required for the first argument to key(). The name must meet the criteria for a QName (see Chapter 12).

The <xsl:key> match Attribute

The match attribute uses a pattern expression to identify the node or set of nodes that will be associated with the key that is being defined. Once the node is matched, a value for the key for that node is assigned according to the specification supplied in the use attribute. Note that variable references (discussed in Chapter 8) are not allowed in the match attribute for <xsl:key>.

The <xsl:key> use Attribute

Once a node has been matched, the particular information that is to be used as the value for the key associated with that node is identified with the use attribute. The value for a key is often the value of an attribute in the element chosen by the pattern expression given for the match attribute. Since the value of the use attribute is a pattern expression, it can reference any node type in the input document. Note that variable references (discussed in Chapter 8) are not allowed in the use attribute for <xsl:key>.

Creating Keys with <xsl:key>

The <xsl:key> element is a top-level element, which means that keys must be defined at the stylesheet level, and cannot be defined in templates. The value of the keyed nodes can be extracted in a template using the key() function. The node-set matched using the match attribute of <xsl:key> is "indexed" prior to processing the input document with template rules. This means that the value of the key does not change after the creation of the key, and is not dependent on the context of a template rule.

Creating keys involves using all three attributes for the <xsl:key> element. The name attribute defines the name of the key, the match attribute is used to select the node-set to associate with the key, and the use attribute selects the value to assign to the key.

For example, to use the value of an attribute node as the value of the key, reference the attribute in the use attribute of the <xsl:key> element:

<xsl:key name="key_name" match="*" use="@href" /> 

In this case, we're assigning a key named "key_name" to each node and assigning a value to the key using the value of the href attribute on that element.

In this example, every element node of the input source tree (designated by the *) will be assigned a key. If the node being matched has an href attribute, the value given for that href will be the key value that is assigned to that node. If the node being matched does not have an href attribute, the value of the key will be null and the key will not be accessible.

Using a version of Markup City that contains houses, we could create keys for the addresses, selecting only those houses that are off of Whitesburg Drive, taking advantage of <xsl:key>'s attributes to make that limitation, as shown in Example 11-3.

Example 11-3 Setting up a set of keys with <xsl:key>.
INPUT: <?xml version="1.0"?> <main>       <parkway>             <thoroughfare>Governor Drive</thoroughfare> <thoroughfare name="Whitesburg Drive">                           <sidestreet name="Bob Wallace Avenue">                           <block name="1st Street">                                 <house address="1200" />                                 <house address="1201" />                                 <house address="1202" />                                 <house address="1203" />                           </block> <block>2nd Street</block>                           <block name="3rd Street">                                 <house address="1100" />                                 <house address="1101" />                                 <house address="1102" />                                 <house address="1103" />                                 <house address="1104" />                                 <house address="1105" />                           </block>                    </sidestreet>                    <sidestreet name="Woodridge Street">                           <house address="5624" />                           <house address="5625" />                           <house address="5626" /> </sidestreet> </thoroughfare> <thoroughfare name="Bankhead">                     <sidestreet>Tollgate Road</sidestreet>                           <block>First Street</block>                           <block>Second Street</block>                           <block>Third Street</block>                     <sidestreet>Oak Drive</sidestreet>             </thoroughfare>       </parkway>       <boulevard>             <block>Panorama Street</block>             <block name="Highland Plaza">                   <house address="3410" />                   <house address="3411" />                   <house address="3412" />                   <house address="3413" />                   <house address="3414" />                   <house address="3415" /> </block>            <block>Hutchens Avenue</block>            <block>Wildwood Drive</block>            <block>Old Chimney Road</block>            <block>Carrol Circle</block>        </boulevard> </main> KEY RULE: <xsl:key name="Whitesburg_houses"       match="//*[@name='Whitesburg Drive']//house"       use="@address" /> 

We've narrowed down the possible houses to be "keyed" by selecting only those that are descended from an element whose name attribute has the value Whitesburg Drive. It is not necessary to know whether Whitesburg Drive is a <parkway>, <thoroughfare>, or <boulevard>. For that matter, @name would be replaced if we did not know what the attribute name was by a generic search for any attribute with the value Whitesburg Drive, using the @* abbreviation in match="//*[@*='Whitesburg Drive']//house".

In any node that matches, the address attribute value would be used as the key, designated by the use="@address".

The resulting keyed object are stored in the processors memory, and can be represented as a table, as shown in Table 11-2.

The keys created here can be described in terms of the three parts mentioned above. There is the key's name, Whitesburg_houses, represented as the title of the table. Then there is the node itself, which in this case is an element identified in the match. Each node is associated with its key, which is chosen in the <xsl:key> element's use attribute, in this case as the address attribute of the house node.

Table 11-2. Whitesburg_houses
Node Key
<house address="1200" /> 1200
<house address="1201" /> 1201
<house address="1202" /> 1202
<house address="1203" /> 1203

Regardless of the kind of object designated by use, its value is converted to a string. If it is a node-set, it is converted to a string that is equivalent to the string value of one or more nodes designated by use.

The <xsl:key> element can be used several times with the same match value. This will add several different keys to each node in the node-set returned by the match, providing several different use values are given for each key on the same matched node. In addition, several keys can all share the same name, but have different match and use values, so that a particular category of information can be accessed several ways.

The nodes that have keys created in our example can be retrieved with the arguments given for the key() function,which is discussed in the next section.

11.1.3.2 The key() XSLT Function

The key() function and <xsl:key> element are interdependent. The key() XSLT function belongs to the node-set function group, returning a node-set from the evaluation of two required arguments, as shown in the following function prototype. The first argument must be a string, which evaluates to the name of the key as defined in the <xsl:key> element. The second argument can be any of the four types of objects node-set, string, Boolean, or number but evaluates to a string, and is used as the test for the value of the key.

Function: node-set key(string, object)
Function Name Function Group Function Return Type Argument Arguments Type
key() Node-set Node-set String Object Required Required

The return value of the key() function is a node-set, and contains the nodes that have a key value equal to the value of the string of the second argument of the key() function. In other words, the value of the second argument is used to retrieve a list of nodes with the same key value.

For example, using the keys for houses set up in the previous section in Example 11-3, we can retrieve the houses that have keys, and ignore the ones that don't, using <xsl:copy-of> to get a copy of the keyed nodes, as follows:

<xsl:template match="house">       <xsl:copy-of select="key('Whitesburg_houses', @address)"/> </xsl:template> 

The result of this template rule would copy only the houses that have a key named 'Whitesburg_houses' with the value equal to the same value as the current <house> element's address attribute.

Note

If you are a programmer, note the similarity of keys to arrays. Arrays have a name (the name of the array), a value (the value of an item in the array), and a return (the content of the array with that particular name and value). In this case, the return is the node that has the key. The only distinction is that an array can be thought to contain an item, whereas with keys, the item (node) has a key attached to it (there is no containership going on).

Think of keys as a way of adding "virtual" attributes to elements without changing the markup. The key name would be the same as an attribute name, and the key value would be the same as an attribute value. This explains why different nodes in a document can have the same key name and the same key value. For example, a key for the number of stories on a house would necessarily be the same for most houses, one, two, or maybe three.

<house stories="2"> <house stories="1"> <house stories="2"> 

Assume you've made a key with the name stories using <xsl:key name="stories" match="house" use="@stories"/>. Using key('stories', '2') will return all the <house> elements with a key of two stories, or the first and the third houses.

Unlike attributes, though, it is possible for one node to have more than one key of the same name, but with a different key value. This is useful if you want have several values on a node, but use the same key name. Let's say, for instance, you are keeping a list of all the houses that have a certain characteristic, such as bay windows. An element could not have two attributes called window. They would each need to be a different attribute name, as shown below.

<house window1="bay" window2="recessed">First House</house> <house window1="gable" window2="bay">Second House</house> <house window1="recessed" window2="gable">Third House</house> 

Defining a key for each window type, however, you only need one name for the key, but you can use multiple values for the use attribute, as follows:

<xsl:key name="window"       match="house"       use="@window1 | @window2" /> 

The name of the node from which you are drawing your key value does not have to match the name of the key itself. If you have a key named window, then the value could be bay, recessed, casement, or gable. Your stylesheet could then say, "Give me all the houses that have bay windows." You wouldn't need to have separate key names for each type of window. This is particularly useful if you have several hundred kinds of windows! Example 11-4 shows a stylesheet using keys to make a report of two kinds of windows.

Using <xsl:copy-of select="key('window', 'bay')"/> would return any houses with bay windows, and <xsl:copy-of select="key('window', 'recessed')"/> would return any houses with recessed windows. Notice that First House is duplicated in the report, because it has both bay windows and recessed windows. There might be quite a few kinds of windows on a given group of houses, but only the ones specified would be selected.

Example 11-4 Using key() to pull nodes with multiple values for the same key.
INPUT: <?xml version="1.0"?> <block> <house window1="bay" window2="recessed">First House</house> <house window1="gable" window2="bay">Second House</house> <house window1="recessed" window2="gable">Third House</house> </block> STYLESHEET: <?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"             version="1.0"> <xsl:output indent="yes"/> <xsl:key name="window"       match="house"       use="@window1 | @window2" /> <xsl:template match="text()"/> <xsl:template match="/"> <xsl:text> Houses with Bay Windows </xsl:text> <xsl:copy-of select="key('window', 'bay')"/> <xsl:text> Houses with Recessed Windows </xsl:text> <xsl:copy-of select="key('window', 'recessed')"/> </xsl:template> </xsl:stylesheet> RESULT: Houses with Bay Windows <house window1="bay" window2="recessed">First House</house> <house window1="gable" window2="bay">Second House</house> Houses with Recessed Windows <house window1="bay" window2="recessed">First House</house> <house window1="recessed" window2="gable">Third House</house> 

11.2 String XSLT Functions

The XSLT string function group includes four functions: system-property(), generate-id(), format-number(), and unparsed-entity-uri().

The system-property() function is not a string function in the purest sense, as it does not necessarily return a string as its function return type, but rather takes a string as a required argument. This function performs a sort of internal diagnostic check for system properties, and its resulting object is controlled by the namespace defining the system property.

The second function, generate-id(), enables the creation of unique identifiers for nodes in the input XML document instance. It can be used, for instance, to create an ID attribute for later use with the id() function.

The third string function, format-number(), works to adjust and control the formatting of numbers in the output. When the third argument to the format-number() function is used, it must be used in conjunction with the <xsl:decimal-format> top-level element.

Finally, the unparsed-entity-uri() function is used to extract PUBLIC or SYSTEM URI values from entities declared in a DTD.

11.2.1 The system-property() XSLT Function

The system-property() XSLT function is used to access the value of the system property named in its one required string argument, shown in the following function prototype. The function returns an object following the evaluation, which is the value of the system property being tested.

System properties can be defined by a namespace, and the value of each system property is controlled by the namespace that defines it. The string argument essentially passes the name of the system property as a query to the XSLT processor to determine its value. If the system value being tested has a prefix for a namespace, that namespace controls the values of the system properties. If no system property exists, the function returns an empty string.

Function: object system-property (string)
Function Name Function Group Function Return Type Arguments Argument Type
system-property() String Object String Required

The W3C specification for XSLT requires that any conforming XSLT processor be able to furnish values for the three specific system properties in the XSLT namespace as follows:

  1. xsl:version Generates the version of XSLT supported by the processor (which, for the time being, remains 1.0).

  2. xsl:vendor Gives the name of the vendor of the XSLT processor.

  3. xsl:vendor-url Provides a string with a URL that identifies the vendor of the XSLT processor's homepage, if that is the resolution of the URL that the vendor defines.

Using <xsl:value-of> in Example 11-5 to get the value of each of these three system properties results in the following for XT and Saxon, respectively.

Example 11-5 Using <xsl:value-of> to extract XSL system properties.
XSLT Instructions: <xsl:value-of select="system-property('xsl:version')"/> <xsl:value-of select="system-property('xsl:vendor')"/> <xsl:value-of select="system-property('xsl:vendor-url')"/> Result Using XT: 1 James Clark http://www.jclark.com/ Result Using Saxon: 1 SAXON 5.5.1 from Michael Kay of ICL http://users.iclway.co.uk/mhkay/saxon/index.html 

11.2.2 The generate-id() XSLT Function

The generate-id() function is used to generate a unique identifier for the first node in a node-set, specified by the node-set argument. It returns a string as its function return type, as shown in the following function prototype. If the optional argument is not provided, the context node is used. If an argument is provided, but contains an empty node-set, the result is an empty string.

Function: string generate-id (node-set?)
Function Name Function Group Function Return Type Arguments Argument Type
generate-id() String String Node-set Optional

The XSLT processor generates the string returned by the generate-id() function. The resulting string can be anything that the XSLT processing software was designed to generate; but, true to the requirements for an ID, it must begin with an alphabetic character.

The processor will always generate the same ID for the same node in document order, and the IDs will conform to the requirement that they be different for different nodes. However, it is possible that the same ID might not be generated for the same node each time the document is processed.

When the node-set argument is given, the ID is generated for the first node of the argument node-set in document order. If the result of evaluating the node-set in the argument is an empty node, the string will also be empty. When the node-set argument is not present, the ID is generated for the context node of the template rule in which the generate-id() function is called.

In Example 11-6, we will begin with the basic city with the new <house>s, which as yet have not been assigned addresses (notice that in this example, we have put the street names into attributes).

Notice, of course, that these are not the most natural-looking addresses when you run this stylesheet using XT, and they seem to be skipping some values. The values generated by the processor are incrementing by node. This is because XT generates IDs by counting nodes, but it counts all the nodes, including the element nodes, attribute nodes, and comment nodes, in the node tree of the entire input document. If there was text inside the <house> elements, the XT processor would also count that, and increment the number for each text node. In our example, the <xsl:strip-space> element is used to remove any additional text nodes that contain whitespace, because they would also increment the node count if not removed. The <xsl:template match="text()"/> removes any text, like Oak Drive, from elements that are not being matched, and <xsl:output indent="yes"/> adds nice formatting to the output. The template rule matching on "block" puts the <block> element in the output, as well as the name attribute for each <block>, and the template rule matching on "house" uses the generate-id() function to generate address attributes for each <house> element in the output.

Example 11-6 Using the generate-id() function.
INPUT: <?xml version="1.0"?> <parkway>              <!-- some thoroughfare's removed for brevity -->       <thoroughfare name="Bankhead">             <sidestreet name="Tollgate Road">                   <block name="First Street">                         <house></house>                         <house></house>                         <house></house>                         <house></house>                         <house></house>                         <house></house>                   </block>                   <block name="Second Street">                         <house></house>                         <house></house>                         <house></house>                         <house></house>                         <house></house>                         <house></house>                   </block>                   <block name="Third Street">                         <house></house>                         <house></house>                         <house></house>                         <house></house>                         <house></house>                         <house></house>                   </block>             </sidestreet>             <sidestreet>Oak Drive</sidestreet>       </thoroughfare> </parkway> STYLESHEET: <?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"                  version="1.0"> <xsl:template match="text()"/> <xsl:output indent="yes"/> <xsl:strip-space       elements="block house parkway thoroughfare sidestreet"/> <xsl:template match="block">       <block name="{@name}">       <xsl:apply-templates />       </block> </xsl:template> <xsl:template match="house">       <house>             <xsl:attribute name="address">             <xsl:value-of select='generate-id()' />             </xsl:attribute>       </house> </xsl:template> </xsl:stylesheet> RESULT: <?xml version="1.0" encoding="utf-8"?> <block name="First Street"> <house address="N9"/> <house address="N10"/> <house address="N11"/> <house address="N12"/> <house address="N13"/> <house address="N14"/> </block> <block name="Second Street"> <house address="N17"/> <house address="N18"/> <house address="N19"/> <house address="N20"/> <house address="N21"/> <house address="N22"/> </block> <block name="Third Street"> <house address="N25"/> <house address="N26"/> <house address="N27"/> <house address="N28"/> <house address="N29"/> <house address="N30"/> </block> 

11.2.3 The format-number() XSLT Function

The format-number() function is used to process a raw number and represent it as a formatted number (string) in the output. The function accepts three arguments and returns a string as its function return type, as shown in the following function prototype. The first two arguments are, respectively, a number and a string. Both arguments are required. The third argument is optional and is also a string.

Function: string format-number (number, string, string?)
Function Name Function Group Function Return Type Arguments Argument Type
format-number() String String Number String String Required Required Optional

The number supplied as the first argument to the format-number() function is converted to a string according to the format pattern indicated in the second argument. In other words, the second argument furnishes the model for the format conversion of the number in the first argument. The second argument is a string model that will bze used to format the number provided by the first argument. It is composed of a specific pattern, using characters derived by reference from the JDK 1.1 specification for numbers. The possible symbols are listed in Table 11-3.

Table 11-3. Formatting symbols for format-number()
Symbol Meaning
0 A digit.
# A digit, where using a zero is displayed as absent.
. A period. Placeholder for decimal separator.
, A comma. Placeholder for grouping separator.
; A semi-colon. Separates formats.
- A dash. Default negative prefix.
% A percent symbol. Multiply by 100 and show as percentage.
? A question mark. Multiply by 1000 and show as per mille.
$ Currency symbol. The currency symbol (#x00A4) is not supported by XSLT implementations of the java.text.DecimalFormat class. Use the real currency symbols for the appropriate country when required.
X A letter or number. Any other characters can be used in the prefix or suffix.
' A single quote. Used to quote special characters in a prefix or suffix.

For example, let's take any number, say 3.14159265358979323. If you wanted to represent this number as a number without any decimal characters, you would use the following:

<xsl:value-of select="format-number('3.14159265358979323', '#')"/> 

This XSLT example would return any digit or digits before the decimal marker (the period "."). It would first, of course, round the numbers according to the rules of the round() function (see Chapter 5). In this case, since rounding doesn't change the number before the decimal marker, the value returned is 3. Since we are using the # symbol, any leading 0 digits (if any) will be dropped (e.g., if you had 003.14159265358979323 as your value).

Adding the decimal point and two digit markers to the second argument would return the "normal" value of pi, or 3.14:

<xsl:value-of       select="format-number('3.14159265358979323', '#.##')"/> 

Let's say you wanted to format a number to be in the form of U.S. currency. The currency symbol is placed in front of the digit marker as appropriate:

<xsl:value-of       select="format-number('3.14159265', '$#.##')"/> 

This would return $3.14.

Of course, the full power of the format-number() function is not realized unless you have really large numbers. For example,

<xsl:value-of select=       "format-number('141592653589793.23', ' US $#,###.##')"/> 

Put the result in your bank account: US $141,592,653,589,793.22. You would lose a penny in the deal because of rounding, but that's not much when you have this kind of bank balance (the authors recommend donation of said pennies en masse to a central fund for lucidity in technical writing).

The third argument of the format-number() function is used to specify a different decimal format than the default. The default decimal format comes from the DecimalFormat[1] class of Java. The format-number() function works closely with the definitions for formatting decimal numbers from the Java Development Kit (JDK 1.1 and later), found in the java.text.DecimalFormat class. This argument requires the use of the <xsl:decimal-format> element, as discussed in the following section.

11.2.4 The <xsl:decimal-format> Top-Level Element

The <xsl:decimal-format> top-level element defines parameters for the display of decimal numbers. Issues such as the European style of commas for decimal notation as opposed to the U.S. period style (e.g., with the decimal-separator attribute) are addressed by the attributes of <xsl:decimal-format>. This element must be present if there is a third argument given for format-number(). It has 11 attributes, as shown in the following element model definition, and is an empty element:

<!-- Category: top-level-element --> <xsl:decimal-format   name = qname   decimal-separator = char   grouping-separator = char   infinity = string   minus-sign = char   NaN = string   percent = char   per-mille = char   zero-digit = char   digit = char   pattern-separator = char /> 

The <xsl:decimal-format> element has a name attribute that is used to assign a unique name to the decimal format being created. If the third attribute of format-number() is used, its value must match one of the named decimal formats. The name allows several different versions of the <xsl:decimal-format> element to be used by the format-number() function. This is useful for localization of the output, or when presenting the same content in several different languages, for example.

The <xsl:decimal-format> element basically allows you to override the default characters used for the symbols in the pattern of the second argument to format-number(), shown previously in Table 11-3.

Quoting from the XSLT specification, with comments as necessary, the attributes for <xsl:decimal-format> are as follows. None of these attributes are required, including the name attribute.

  1. name Specifies the name of the named decimal-format being declared.

    The name is used as the third option for the format-number() function to call a specific named decimal format. When a name attribute is not used on the <xsl:decimal-format> element, the decimal format defined by that element is used as the default decimal format.

  2. decimal-separator Specifies the character used for the decimal sign; the default value is the period character (.).

    This determines the actual character used to separate the real number from the decimal part of the number. This would be used, for instance, to make the European notation form of a number using a comma instead of a period. Its representation in the format pattern is the same as its output value that is, it looks the same in the output as it does in the pattern.

  3. grouping-separator Specifies the character used as a grouping (e.g., thousands) separator; the default value is the comma character (,).

    This determines the actual character used to separate groups of numbers. This is normally a comma, but might also be a period in some other countries or languages. Its representation in the format pattern is the same as its output value.

  4. percent Specifies the character used as a percent sign; the default value is the percent character (%).

    This determines the actual output character used to represent a percent symbol. Its representation in the format pattern is the same as its output value.

  5. per-mille Specifies the character used as a per-mille sign; the default value is the Unicode per-mille character.

    This determines the actual output character used to represent a per-mille symbol. Its representation in the format pattern is the same as its output value.

  6. zero-digit Specifies the character used as the digit zero; the default value is the digit zero (0).

    This determines the actual output character used to represent the digit zero. In some cases, for example, an X might be used to block out the zeros: $123.XX.

  7. digit Specifies the character used for a digit in the format pattern; the default value is the number sign character (#).

    This character is only used in the format pattern to represent digits. It is replaced by actual numbers in the output.

  8. pattern-separator Specifies the character used to separate positive and negative subpatterns in a pattern; the default value is the semi-colon character (;).

    When more than one format pattern applies to a given number, the patterns can be separated using this symbol. The processor will select the correct pattern from the values provided to format the output correctly.

  9. infinity Specifies the string used to represent infinity; the default value is the string Infinity.

    This specifies the particular character that represents infinity, which may appear in the result of formatting the number.

  10. NaN Specifies the string used to represent the NaN value; the default value is the string NaN.

    This specifies the particular characters or string that may appear in the result of formatting the number when the given value does not evaluate to a number.

  11. minus-sign Specifies the character used as the default minus sign; the default value is the hyphen-minus character (-, #x2D).[2]

    This specifies the particular character that may appear in the result of formatting the number if the number supplied is negative.

As an example, a decimal format named "dashed" can be created with the <xsl:decimal-format> top-level element as follows:

<xsl:decimal-format name="dashed" decimal-separator="," grouping- separator="-" digit="X"/> 

Using our previous example, we add the third argument to format-number() for the name of the decimal format we created, and change the pattern to fit the new format:

 <xsl:value-of select="format-number('141592653589793.23', 'X- XXX.XX', 'dashed')"/> 

This would generate the output 141-592-653-589-793,22.

Note that the <xsl:decimal-format> element and the third argument to the format-number() function are not implemented by XT.

11.2.5 The unparsed-entity-uri() XSLT Function

The unparsed-entity-uri() XSLT function is used to access the PUBLIC or SYSTEM value of an entity's URI. It has a function return type of string and requires one argument of type string, as shown in the following function prototype:

Function: string unparsed-entity-uri (string)
Function Name Function Group Function Return Type Arguments Argument Type
unparsed-entity-uri() String String String Required

The string returned by the function is the URI of the unparsed entity, which resolves to either the public identifier or the system identifier. Normally, the public identifier will be returned, depending on the preference of the XSLT processor being used, unless there is no public identifier declared. The declaration of the entity must be in the DTD, and the entity must be called using an entity reference in the document being processed, otherwise the function will return an empty string. If the URI returned by the function is a relative URI, it will be converted to an absolute URI using the base URI of the document that contains the entity declaration.

11.3 The Boolean XSLT Function Group

The Boolean XSLT function group addresses a circumstance that might well have crossed your mind. Specifically, if XSLT is extensible and different XSLT processors have their own specific extension elements and functions, what happens when an extension from one processor is called in an XSLT stylesheet being run on another processor that doesn't support that extension? Further, if this can and sometimes does generate an error that terminates the processing of the given XSLT stylesheet, is it possible to prepare in advance for this eventuality?

Many things in XSLT are contingent on which processor you are using, and the Boolean functions for XSLT are quite essential if your stylesheets are to be used in multiple environments, which might employ different XSLT processors. For instance, an XSLT stylesheet for a client who is likely to use Saxon might also have to be used in some places where only XT is running.

This is exactly the eventuality addressed by the two Boolean core functions for XSLT, which test if a given extension function or element is supported by the processor being used.

The element-available() and function-available() functions provide a contingency plan, if you will, for what happens in the event that a function or instruction element is not available in the chosen XSLT processing software. If a well-formed, conforming XSLT stylesheet includes instruction elements or functions that are supported by the chosen XSLT processor, all is well. If the processor doesn't support them, however, and the XSLT stylesheet uses those elements or functions (whether it hinges in part or in total on those elements or functions), the processor will stop and signal an error.

Note

It is not an error to include unsupported elements or functions in a template if that template is not instantiated. The processor will not test a function unless it is actually used in an expression that is instantiated.

11.3.1 The element-available() XSLT Function

The element-available() XSLT function is used to test whether the XSLT processor being used supports the instruction element or extension instruction element identified in the argument. It returns a Boolean as its function return type, and requires a single argument in the form of a string, as shown in the following function prototype:

Function: boolean element-available (string)
Function Name Function Group Function Return Type Arguments Argument Type
element-available() Boolean Boolean String Required

The string supplied for the argument of the element-available() function must be the name of the element being tested. If the name of the element has a namespace prefix that is the XSLT namespace (xsl), then the test is for an XSLT instruction element being supported. If the namespace is null, the element-available() element will return false. Any other namespaced name is a test for an extension element.

The most common use for this function is in combination with the <xsl:choose> instruction element. Sections of the stylesheet that are associated with an extension element that may not be supported by a processor can be contained within an <xsl:choose>, using <xsl:when> and <xsl:otherwise>. With the use of the element-available() function as the value of the test attribute for <xsl:when>, the processor will know when to handle it and when to ignore it. The <xsl:otherwise> gives an alternative action in case the result of the <xsl:when> test is not true.

In Example 11-7, we use the <xsl:document> element, which is defined in XSLT 1.1 WD, and may not be supported by some processors.

This stylesheet fragment keeps the <xsl:document> element from processing if the extension element is not supported by the processor. This example is presented as a full stylesheet in Example 13-6 of Chapter 13.

Example 11-7 Using the element-available() function.
<xsl:when test="element-available('xsl:document')">       <xsl:document href="{@name | text()}.html">             <html>                    <head>                    <title>                           <xsl:value-of select="@name | text()"/>                    </title>                    </head>                    <body>                    <h2>                           <xsl:value-of select="@name | text()"/>                           </h2>                           <xsl:apply-templates/>                    </body>             </html>       </xsl:document> </xsl:when> 

Example 11-8 shows a stylesheet to test each XSLT instruction element. Note that this stylesheet will return an error if using XT because the element-available() function is not implemented by XT.

11.3.2 The function-available() XSLT Function

The function-available() XSLT function checks for the support of a given function by the XSLT processor being used, whether it is an extension function or an XPath or XSLT function. It has a single required argument in the form of a string, as shown in the following function prototype. The value of the string should be a QName that expands to the name of the function whose support is being tested. The object returned is Boolean true if the function is supported, and false if it is not.

The function-available() XSLT function can be used to test if the version of the XSLT processor being used supports XSLT or XPath functions, as well as whether an extension function is supported. If a function is used that is not supported, the processor will generate an error when the template or instruction calling that function is instantiated. If a function that is not supported is not called, it will not result in an error.

Example 11-8 Using the element-available() to test each XSLT instruction.
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"       xmlns:go="my-extensions"                 version="1.0"> <xsl:output method="text"/> <xsl:template match="/"> <xsl:text> Supports  &lt;xsl:apply-imports> = </xsl:text> <xsl:value-of select="element-available('xsl:apply-imports')"/> <xsl:text> Supports  &lt;xsl:apply-templates> = </xsl:text> <xsl:value-of select="element-available('xsl:apply- templates')"/> <xsl:text> Supports  &lt;xsl:attribute> = </xsl:text> <xsl:value-of select="element-available('xsl:attribute')"/> <xsl:text> Supports  &lt;xsl:call-template> = </xsl:text> <xsl:value-of select="element-available('xsl:call-template')"/> <xsl:text> Supports  &lt;xsl:choose> = </xsl:text> <xsl:value-of select="element-available('xsl:choose')"/> <xsl:text> Supports  &lt;xsl:comment> = </xsl:text> <xsl:value-of select="element-available('xsl:comment')"/> <xsl:text> Supports  &lt;xsl:copy> = </xsl:text> <xsl:value-of select="element-available('xsl:copy')"/> <xsl:text> Supports  &lt;xsl:copy-of> = </xsl:text> <xsl:value-of select="element-available('xsl:copy-of')"/> <xsl:text> Supports  &lt;xsl:element> = </xsl:text> <xsl:value-of select= "element-available('xsl:element')"/> <xsl:text> Supports  &lt;xsl:fallback> = </xsl:text> <xsl:value-of select= "element-available('xsl:fallback')"/> <xsl:text> Supports  &lt;xsl:for-each> = </xsl:text> <xsl:value-of select="element-available('xsl:for-each')"/> <xsl:text> Supports  &lt;xsl:if> = </xsl:text> <xsl:value-of select="element-available('xsl:if')"/> <xsl:text> Supports  &lt;xsl:message> = </xsl:text> <xsl:value-of select="element-available('xsl:message')"/> <xsl:text> Supports  &lt;xsl:number> = </xsl:text> <xsl:value-of select="element-available('xsl:number')"/> <xsl:text> Supports  &lt;xsl:processing-instruction> = </xsl:text> <xsl:value-of select="element-available('xsl:processing- instruction')"/> <xsl:text> Supports  &lt;xsl:text> = </xsl:text> <xsl:value-of select="element-available('xsl:text')"/> <xsl:text> Supports  &lt;xsl:value-of> = </xsl:text> <xsl:value-of select="element-available('xsl:value-of')"/> <xsl:text> Supports  &lt;xsl:variable> = </xsl:text> <xsl:value-of select="element-available('xsl:variable')"/> </xsl:template> </xsl:stylesheet> RESULT using Saxon: Supports  <xsl:apply-imports> = true Supports  <xsl:apply-templates> = true Supports  <xsl:attribute> = true Supports  <xsl:call-template> = true Supports  <xsl:choose> = true Supports  <xsl:comment> = true Supports  <xsl:copy> = true Supports  <xsl:copy-of> = true Supports  <xsl:element> = true Supports  <xsl:fallback> = true Supports  <xsl:for-each> = true Supports  <xsl:if> = true Supports  <xsl:message> = true Supports  <xsl:number> = true Supports  <xsl:processing-instruction> = true Supports  <xsl:text> = true Supports  <xsl:value-of> = true Supports  <xsl:variable> = true 

Although it is not an error to have an expression as the value of an argument, it must be a string value. Some implementations may not support expressions as arguments and will return a false value. For example, using function-available(string(concat('doc', 'ument'))) is technically the same as using function-available('document'), yet it may result in a value of false even if the document() function is supported.

Example 11-9 shows a test for each XSLT function using the function-available() XSLT function. Of course, if the processor doesn't support the function-available() function, this stylesheet will not work. However, processors are required to support this function according to the XSLT specification.

Function: boolean function-available (string)
Function Name Function Group Function Return Type Arguments Argument Type
function-available() Boolean Boolean String Required
Example 11-9 Using function-available to test XSLT function support.
<?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:text> Supports document() = </xsl:text> <xsl:value-of select="function-available('document')"/> <xsl:text> Supports current() = </xsl:text> <xsl:value-of select="function-available('current')"/> <xsl:text> Supports key() = </xsl:text> <xsl:value-of select="function-available('key')"/> <xsl:text> Supports system-property() = </xsl:text> <xsl:value-of select="function-available('system-property')"/> <xsl:text> Supports generate-id() = </xsl:text> <xsl:value-of select="function-available('generate-id')"/> <xsl:text> Supports format-number() = </xsl:text> <xsl:value-of select="function-available('format-number')"/> <xsl:text> Supports unparsed-entity-uri() = </xsl:text> <xsl:value-of select="function-available('unparsed-entity- uri')"/> <xsl:text> Supports element-available() = </xsl:text> <xsl:value-of select="function-available('element-available')"/ > <xsl:text> Supports function-available() = </xsl:text> <xsl:value-of select="function-available('function- available')"/> </xsl:template> </xsl:stylesheet> Result Using Saxon: Supports document() = true Supports current() = true Supports key() = true Supports system-property() = true Supports generate-id() = true Supports format-number() = true Supports unparsed-entity-uri() = true Supports element-available() = true Supports function-available() = true Result Using XT: Supports document() = true Supports current() = false Supports key() = false Supports system-property() = true Supports generate-id() = true Supports format-number() = true Supports unparsed-entity-uri() = true Supports element-available() = false Supports function-available() = true

[1] DecimalFormat is a concrete subclass of NumberFormat for formatting decimal numbers. It allows for a variety of parameters and localization to Western, Arabic, or Indic numbers. You can find more information about the Java DecimalFormatclass at http://java.sun.com/products/jdk/1.1/docs/api/java.text.DecimalFormat.html.

[2] #x2D is your plain, old, everyday, bread-n-butter minus sign.

CONTENTS


XSLT and XPATH(c) A Guide to XML Transformations
XSLT and XPATH: A Guide to XML Transformations
ISBN: 0130404462
EAN: 2147483647
Year: 2005
Pages: 18

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net