Skip to main content

If you don't have an IBM ID and password, register here.

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. This profile includes the first name, last name, and display name you identified when you registered with developerWorks. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

All information submitted is secure.

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

Planning to upgrade XSLT 1.0 to 2.0, Part 4: The toolkit for XSLT portability

How XSLT processors cope with the unknown

David Marston, Software Engineer, IBM, Software Group
David Marston has worked with XML technologies since late 1998, particularly on standards conformance. Over his 25+ years in the computing business, he has been involved with all aspects of software development. He is a graduate of Dartmouth College and a member of the ACM. He is on the Next-Generation Web team at IBM Research. You can contact him at David_Marston@us.ibm.com.
Joanne Tong, Software Developer, IBM, Software Group
Joanne Tong is a developer working on IBM's XSLT processors in the IBM Toronto lab. She is currently an editor of the W3C XSLT 2.0 and XQuery 1.0 Serialization specification and is an active member of the XSL working group. You can contact her at joannet@ca.ibm.com.

Summary:  If you are concerned with the adoption of XSLT 2.0 and what will happen to your legacy stylesheet code, this is the article you need. It focuses on those features of 2.0 that address cross-version compatibility with 1.0. It explains how 1.0 and 2.0 processors recognize XSLT instructions and the vendor's implementation-specific instructions (if any), distinguishing them from elements that should not be directives to the processor. The article includes a survey of all portability tools such as fallback, function availability tests, and the new use-when attribute. To read the other articles in this series, go to the Planning to upgrade overview page.

View more content in this series

Date:  20 Feb 2007
Level:  Intermediate

Comments:  

About this series

XSLT 2.0, the latest specification released by the World Wide Web Consortium (W3C), is a language for transforming XML documents. It includes numerous new features, with some specifically designed to address shortcomings in XSLT 1.0. In this collection of articles, you'll get a high level overview and an in-depth look at XSLT 2.0 from the point of view of an XSLT 1.0 user who wants to fix old problems, learn new techniques, and discover what to look out for. Examples derived from common applications and practical suggestions are provided if you wish to upgrade. To help you begin to use XSLT 2.0, migration techniques will be provided.


One stylesheet can be executed by several processors

This article will present details of all the XSLT constructs available for mixing version 1.0 and 2.0 features, which are needed for most upgrading tactics discussed in Part 2 of this series. (See the Resources section for links to prior parts.) In essence, this is a toolkit for you to make your stylesheets portable, by giving them ways to cope with unknown features. Many of the techniques also apply to portability of a stylesheet between XSLT processors that support different extensions.

XSLT 2.0 expands upon XSLT 1.0 in several ways: new elements, new attributes on old elements, new XPath operators, new functions, and new datatypes. The 1.0 processor would not recognize the new constructs and would raise errors unless you use the tools described here to overcome the errors. A 1.0 processor can accept a 2.0 stylesheet because the namespace URI (Universal Resource Identifier) for XSLT elements has not changed for 2.0; only the (mandatory) version number has changed. In other words, the elements of XSLT 1.0 and 2.0 are commingled, but the 2.0 set is larger. When Forwards Compatibility (FC) is in effect, the processor must assume that XSLT element names it does not recognize might be legitimate for a future version, and it must ignore such elements, except as noted in this article. This principle holds for both 1.0 and 2.0 processors.

When a stylesheet processor encounters an unrecognizable function, operator, attribute, or element in the XSLT namespace, the result can either be an error, to ignore the construct, or to execute an alternative path. The error is often the default, even though it is the least desirable if your goal is portability. If the construct is legal syntax in one version, but unsupported in an older (or newer) version, the desirable outcome is often to choose an alternative path that makes sense and accomplishes the nearest equivalent effect. Where the default outcome is an error, the stylesheet writer will have to be aware of the differences in XSLT versions, and future-proof and/or past-proof the stylesheet (especially when he or she does not know up front which version of XSLT processor performs the transformation). The toolkit available to the stylesheet writer in XSLT 2.0 to future-proof or past-proof a stylesheet consists of:

Of these, all but use-when existed in 1.0, but most have been slightly altered for 2.0, and the version attribute has been greatly expanded. The applicability of conditionals has been curtailed for version 2.0 (and presumably for future versions, should there be any). Before reading about the toolkit, you should know a couple concepts that are new in the XSLT 2.0 specs: static error checking and standard attributes.


Scanning for stylesheet errors

After a processor consolidates a stylesheet from all the imported and included modules, it goes through various steps to prepare for transformation. One such step is to scan for static errors, which are situations that will always be erroneous regardless of the transformation input. Included among the static error conditions are unknown XSLT elements, attributes, and functions. Another kind of static error is where the element or attribute is recognized, but has been placed where it is not allowed. Each tool in the toolkit takes effect either before or after the static error checking phase, and the ramifications are covered in this article.


Standard attributes and scoping

If you understand the scoping of XML namespaces, then you would readily understand the scoping used in stylesheets. (If not, scoping is defined after Table 1.) In XSLT 1.0, a limited form of scoping was used for extension-element-prefixes and exclude-result-prefixes, and now those attributes have been joined by several others in a new classification called Standard Attributes.

In XSLT 1.0, most but not all elements could take attributes, which were always specified anew for each element on which they appeared. XSLT 2.0 defines a collection of standard attributes, and these attributes can appear on any element, including elements like xsl:choose that otherwise take no attributes. Standard attributes also take effect on Literal Result Elements (LREs; see the notes about LREs for more explanation), in which case the name is qualified to the XSLT namespace. For example, the version attribute can appear on an XSLT element, and xsl:version can appear on LREs. (The prefix is needed because non-namespaced attributes on LREs are Literal Result Attributes that propagate to the result.) There are also some attributes in the xml namespace (xml:lang, xml:space, xml:id, xml:base), which can appear on any XSLT element. Some of these attributes affect the results of a transformation. If they are defined on an LRE, then they are copied to the result tree.


Table 1. Standard attributes
NameBrief DescriptionEffect of nesting

default-collation

Collation to use when none specified in instruction or function

override

exclude-result-prefixes

Suppresses namespace declarations (nodes) in output

cumulative

extension-element-prefixes

In a sequence constructor, designates namespaces for elements that are to be treated as extension instructions rather than Literal Result Elements (LREs). See the notes about instructions for more information.

cumulative

use-when

Allows an element to be included or excluded from the stylesheet. This article includes a full discussion of how to use it.

The first one whose condition is false excludes all inner content. As long as the conditions are true, nesting continues.

version

Sets the XSLT version of the stylesheet, module, or a sub-tree.

override

xpath-default-namespace

Sets the namespace assumed for unprefixed elements in an XPath expression.

override

This article discusses version and use-when, and mentions extension-element-prefixes. The term instruction is one of a handful of XSLT constructs explained in the structure table (Table 2).

Explanation of scoping

When an XSLT element defines a standard attribute, the effects of the standard attribute are applied to its descendent elements unless the descendent element defines the same standard attribute with a different value. Thus, for any given element on a stylesheet that does not define the standard attribute on itself, it inherits the standard attributes from its closest ancestor element that defines them. The scoping of these attributes is determined statically. That means a descendent element only inherits the standard attribute if it is defined on the same stylesheet module, according to the XML structure of the document, rather than the structure of how an XSLT processor would execute the stylesheet elements. For example, if there are two templates defined in a stylesheet module, where one template contains an xsl:call-template with an attribute version="1.0", the other named template, when called, is not affected by the attribute version="1.0". The reason is that the scoping of the attribute version="1.0" only applies to the xsl:call-template element and its own descendants (for example, xsl:with-param). It does not affect the named template that is called because that template, from the point of view of the XML document, is not a descendent of the xsl:call-template element. Thus, the named template's xsl:template must also set an attribute version="1.0" in order to process this template in backwards compatibility mode.


The Toolkit for Mixing Versions

Future-proofing is often like extension-proofing, so you can use a lot of the tools below to enhance portability of stylesheets against various differences, not just versions. The similarity is that both provide a way to cope with unknown elements and functions; the difference is that for future-proofing, the unknowns are in the XSLT namespace.

Broader uses for the version attribute

Backwards compatibility (BC) and FC modes are always triggered by the version attribute, not by any processor switch or launch-time option.

A 2.0 processor might support the Backwards Compatibility (BC) feature module, at the vendor's option, in which case the stylesheet can have version="1.0" and it will not result in an error. In addition to its familiar place on xsl:stylesheet, that attribute is recognized by a 2.0 processor on inner elements, as described in the section on scoping standard attributes. BC mode is in effect when the element has a version number, either due to its own version attribute or through scoping, that is lower than the version of the processor.

All XSLT processors, including 1.0 processors, are required to support Forwards Compatibility (FC), which is where the version number on the stylesheet is higher than the version of the processor. When FC is in effect on a stylesheet, the processor must ignore unknown XSLT declaration elements and perform fallback on any unknown XSLT instruction elements, when fallback actions have been specified. (The distinction between instructions and declarations is explained in the structure table.)

In XML, attributes with unqualified names are typically presumed to be meaningful to the element containing them, and XSLT follows that practice. An unknown non-namespace-qualified attribute on an XSLT element raises an error, unless FC mode is in effect. In XSLT 2.0, there are 16 elements that have new attributes they didn't have in 1.0, not counting the standard attributes that can be anywhere. Fortunately, in no case did an attribute that was optional in 1.0 became mandatory in 2.0, nor are any brand new attributes now mandatory on old instructions. Note, however, that in a few cases, an instruction that existed in 1.0 was expanded for 2.0 in a way other than through its attributes. In particular, xsl:apply-imports, xsl:key, xsl:sort, and xsl:value-of had no children under 1.0 but do under 2.0, while xsl:param has new parent elements, and it can be required to have no children, depending on its parent.

The transformation logic controlled by XSLT elements in FC or BC mode can differ from the same elements outside of those modes. XSLT 1.0 and 2.0 specifications (see Resources for links) describe the differences and how to use them. As a general rule, BC only has an effect on an XSLT element where it is specifically documented in the 2.0 family of specs.

Remember that xsl:output/@version is different. It sets the version number of the output document markup, such as the XML version for XML output. The next article in this series will include an example for how to deal with xsl:output.

The xsl:fallback instruction

When an XSLT 1.0 or 2.0 processor, executing in FC mode, encounters an instruction in the XSLT namespace where it is not permitted, it should throw an error unless this element has at least one xsl:fallback child element. The presence of xsl:fallback indicates to the processor that rather than throwing an error, it should execute the sequence constructor (set of instructions) in the xsl:fallback instruction and continue processing. This future-proofing mechanism for XSLT instructions is available when the containing element either specifically allows xsl:fallback or has a sequence constructor. A simple example is when a 1.0 processor executes a 2.0 stylesheet template and encounters an xsl:document instruction. The 1.0 processor simply ignores all children except the xsl:fallback elements and executes those in order. If the 2.0 instruction specifically allows xsl:fallback but does not have a sequence constructor, such as the xsl:analyze-string instruction, the 1.0 processor also ignores xsl:matching-substring and xsl:non-matching-substring (the only permissible children), and executes the sequence constructor in the xsl:fallback element. (The only difference is that the xsl:fallback elements have to be the last children relative to xsl:matching-substring and xsl:non-matching-substring to avoid a static error when executed by a 2.0 processor, even though a 1.0 processor does not care about the ordering of xsl:fallback relative to its siblings.) If an xsl:function element has an xsl:fallback instruction, then an XSLT 1.0 processor ignores the xsl:function element entirely and does not execute its xsl:fallback. That is because the fallback mechanism only works for instruction elements, not declarations. (See the structure table and the following remarks for details about "instruction" and "declaration" elements in XSLT.)

Note that the text about when the fallback mechanism is applied in the XSLT 2.0 spec is refined compared to the XSLT 1.0 spec. A scenario where this change makes a difference is when the stylesheet writer wishes to pass an xsl:with-param value within xsl:apply-imports in those cases where the stylesheet is processed by a 2.0 processor, and rely on the default value of the template parameter if the processor is 1.0. (Note that 1.0 did not allow xsl:with-param inside xsl:apply-imports.) Theoretically, one could accomplish this by adding an emptyxsl:fallback child in the xsl:with-param element to avoid an error in 1.0. This is permissible because the fallback mechanism applies when "it is an element in a template and XSLT 1.0 does not allow such elements to occur in templates" according to the XSLT 1.0 specification. In XSLT 2.0 however, the fallback mechanism applies where "an element in the XSLT namespace appears as part of a sequence constructor." Since the xsl:with-param is not part of a sequence constructor of xsl:apply-imports, the fallback mechanism is not applicable.

The text in XSLT 2.0 might seem irrelevant for this particular example, since a 1.0 processor naturally implements the FC behavior as dictated by the XSLT 1.0 specification. In reality, this might not be the case. Since XSLT 2.0 will be the first recommendation since XSLT 1.0, many existing implementations of XSLT 1.0 did not have the need to implement FC until the 2.0 specification became more commonly used. Thus, this feature might be unsupported or partially supported. When the time comes to implement this feature, the implementor can choose to support the fallback mechanism only where its use is more obvious, such as within new 2.0 instructions (such as xsl:document or xsl:analyze-string) and postpone implementing xsl:fallback in less apparent constructs like within xsl:with-param. Thus, for this particular scenario, the stylesheet writer should avoid using xsl:fallback inside xsl:with-param, and instead apply xsl:choose to choose between xsl:apply-imports with and without xsl:with-param depending on the processor version. (The system-property function is used to check the processor version.)

The xsl:fallback instruction will perform as expected for the following new-for-2.0 instructions: xsl:analyze-string, xsl:document, xsl:for-each-group, xsl:namespace, xsl:next-match, xsl:perform-sort, xsl:result-document, and xsl:sequence. All are instructions and many also contain a sequence constructor, which is a collection of instructions.

Since xsl:fallback offers general protection against unknown instructions, it works in extension instructions, and does not require FC mode for falling back on instruction elements that are not in the XSLT namespace. (There is the possibility of nested xsl:fallback elements, where you guard against a 2.0 instruction and an extension instruction.) It is worth noting, though, that xsl:fallback only applies to one instruction at a time. Therefore, the xsl:fallback element should contain whatever is needed to substitute for the single instruction that contains it.

The use-when attribute and element filtering

The attribute use-when is a new 2.0 standard attribute that can be set on any XSLT element. The attribute value is an XPath expression that results in a boolean after evaluation. If the result is false, then the processor excludes the element and its descendants in the stylesheet. This is a very useful tool that allows the stylesheet writer to exclude completely certain elements, templates, or entire stylesheet modules from the transformation if an XPath condition is not met. For those processors that have an explicit compile phase, use-when filtering is intended to avoid compiling blocks of code that the processor couldn't execute. Since this attribute is meant to be evaluated at the start of the static analysis phase (before scanning for static errors and before an input source document is needed), there are restrictions on the context information exposed to the processor when evaluating the XPath expression. For example, a variable reference in the expression results in an error even though the element is positioned in a template where the variable is in scope. Some key differences are:

  • Can't use or detect types defined in an imported schema
  • Can't check the availability of stylesheet functions, but you can check for vendor-written extension functions built into the processor
  • Can't make references to any variables or params, even if seemingly in scope
  • Can't check the availability of documents, text files, and collections
  • Can't rely on BC mode when evaluating the expression

Refer to part 3.12 of the XSLT 2.0 specification (see Resources) for a complete list of context information exposed during use-when attribute evaluation, but note that the system-property() and availability functions discussed below are available to use. A use-when test can also help you choose collations, as long as it includes an expression that will tell you which collations are available. One possibility is to use the processor identification, as discussed under the system-property function.

The use-when attribute can be used for forwards and backwards compatibility processing. The drawback is that a 1.0 processor would not understand this attribute, and would throw an error if the stylesheet has attribute version = "1.0" (that is, not processed in FC mode). To write a stylesheet that will work with 1.0, 2.0, and a future version, then you can combine conditional and use-when to avoid static errors no matter which version of processor you are using. The next article in this series will show how to deal with these limitations.

Caution: User-defined Data Elements (UDDEs) are not required to support use-when; the vendor can choose whether to support it on UDDEs and extension instructions. (These elements are described in the structure table in this article.) If you need to exclude a UDDE and the vendor indicates that use-when on UDDEs is not supported, rather than just have it be ignored, you can put the UDDE in an included stylesheet module, and put the @use-when on the xsl:include. If you need to exclude an extension instruction, the safest approach is to have alternative templates and apply @use-when filtering at the template level.

Conditional branching in 1.0 and 2.0

The conditional instructions xsl:if and xsl:choose have the advantage over @use-when that these constructs existed in XSLT 1.0. Thus, they can be used for excluding code for version 1.0, rather than version 2.0 or greater, where the use-when attribute is employed. Using the use-when attribute to filter constructs has the benefit that if the constructs within might result in an error (because the current processor's version does not support that construct), then the error must never occur because use-when filtering happens before the scan for static errors. A downside of @use-when is that certain context information is not available to the XPath expression inside @use-when but is available for @test in xsl:when. However, 2.0 processors must throw an error for any invalid content (other than unknown extension functions in certain situations) in a sequence constructor, even if the content is supposedly guarded by an xsl:choose that tests an appropriate boolean value. If that policy were to continue into higher versions, your stylesheets might have problems with obsolete guarding code. In 2.0, xsl:choose can only avoid raising errors when all branches have no static error. For a 2.0 processor, the only potential invalid content in a 1.0-legacy stylesheet is either a syntactic oddity or, in some situations, the rarely-used namespace axis. (See Part 3 of this series for more about support of the namespace axis.) The conditionals are instructions and therefore you can only place them in sequence constructors, while use-when is a standard attribute that can go on any XSLT element, including the ones that are not instructions.

For illustration, here are three ways to determine if a processor implements the 1.0 or 2.0 specification as a boolean value for either the use-when attribute or conditional elements (xsl:if and xsl:choose).

  • system-property('xsl:version') = '2.0' returns true for a 2.0 processor and is normally the preferred form, for readability.
  • function-available('unparsed-text') returns true for a 2.0 (and later) processor
  • element-available('xsl:for-each-group') returns true for a 2.0 (and later) processor

You can use the latter two where the one function or element given as the argument is the only feature in the code block that might not be supported.

The function-available() test

As with 1.0, the set of functions in XSLT 2.0 is extensible. You can supplement the mandatory set of built-in functions in several ways, and use function-available() to verify the availability of functions from any source, including built-in ones. XSLT 2.0 requires support for all the functions in the F&O spec (see Resources), just as XSLT 1.0 required support for all the XPath 1.0 functions, and XSLT adds in its own functions in each version. The XSLT-only functions for 2.0 are: current-group, current-grouping-key, regex-group, document, unparsed-text, unparsed-text-available, key, format-number, format-dateTime, format-date, format-time, current, unparsed-entity-uri, unparsed-entity-public-id, generate-id, system-property, function-available, type-available, and element-available.

The signature and utility of the function-available function has changed in XSLT 2.0. You can still use this function in an expression to determine if a particular built-in or extension function is supported as the stylesheet element is being processed. In XSLT 2.0, you can use a second argument to further check if a particular function that supports a specific number of arguments, or arity, is supported. The utility of this function has also expanded and contracted at the same time. It has expanded in a sense that it can detect a greater variety of in-scope functions, whether used within a use-when attribute or not. It can always detect if a built-in function is supported, defined from both the F&O and XSLT 2.0 specifications. Vendor-provided extension functions should always be reported as available in that vendor's processor (the node-set function for 1.0 is an example). It can also detect if a constructor function of a schema-type is supported; more about that in a moment. Finally, if used outside of the use-when attribute, it can also detect if a user-defined stylesheet function is supported. (See Part 1 of this series for more about stylesheet functions.)

Though these expansions are useful, the application of function-available() has contracted at the same time. When a stylesheet processor analyses a stylesheet for static errors, it will look for syntaxes that it does not understand. If an element is not processed in BC mode and not guarded by a suitable use-when attribute, then the processor throws a static error if it finds a function that it does not understand in an XPath expression. For example, in your sequence constructor within a template, you want to add an xsl:choose to check if an extension function is supported using function-available(). If it is not supported, then you define the alternate behavior in the xsl:otherwise. This is a typical scenario of how function-available is used in XSLT 1.0. Unfortunately, unless the extension function is always supported (which defeats the purpose of checking for it in the first place), the evaluation of this stylesheet by a 2.0 processor during static-error checking results in an error if the extension function is not supported. To get around this problem in 2.0, use the use-when attribute instead of xsl:choose. That is because the evaluation of the use-when attribute occurs before static-error checking. Thus, it is not recommended to use function-available() with xsl:choose and xsl:if unless it is in BC mode.

Since a function call is usually just a part of an XPath expression, an unknown function causes the execution of the entire XPath expression to fail. Furthermore, XPath expressions always occur as attribute values, so the scope of any exclusion is the element containing the attribute in question. Unknown functions are not guarded by FC mode; they require explicit guards against their inadvertent execution. Thus, checking function-available() must occur outside of the attribute that holds the XPath expression (rather than using an IfExpr) and should be used in conjunction with @use-when for future proofing, or a combination of xsl:choose and @use-when for future and past-proofing. The next installment in this series will include an example of that combination.

A 2.0 processor with Schema Awareness can also handle user-defined datatypes, including constructor functions for those datatypes that are atomic and derived from primitive datatypes. This is new to XSLT 2.0 and using the new type-available() function will accomplish the same task as checking availability of the constructor function. For example, if you used xsl:import-schema to make the processor aware of your my:envelope-number datatype, derived from the known xs:decimal datatype, then XPath expressions in that stylesheet can use my:envelope-number(decimal) as an additional available function. The type-available() function can test whether a particular datatype definition has been loaded into the context, whether or not that type has a constructor function. Do not use this function with use-when because the type definitions haven't been imported yet. Continuing the example, neither function-available('my:envelope-number') nor type-available('my:envelope-number') will work with use-when.

You can use function-available() with use-when filtering (for 2.0 and forward), though that might be better for extension functions than for testing functions built in to XSLT and XPath. Use it for a single built-in if that makes the code readable. Namespace-qualified names of functions always signal an extension function in 1.0, at least according to the 1.0 spec. It is not clear whether all implementers of 1.0 processors noticed this, but it has interesting uses for stylesheets that will be run by both 1.0 and 2.0 processors.

The element-available() test

The element-available() function has remained unchanged from 1.0 to 2.0. It is only about "instructions" (defined in the structure table). Likely uses are in @use-when or in xsl:choose if the other branch is not a static error. Reminder: To work around a single instruction that might be unknown, the fallback mechanism is safer, because both 1.0 and 2.0 specs agree that the element in question must not raise a static error as long as FC mode is in effect. Bonus: You don't need to bother with element-available(), because that is essentially the only condition xsl:fallback ever uses as a criterion.

The system-property() tests

This article discusses the xsl:version keyword, one of several available in the system-property function. New for 2.0, this function can also test for all three optional feature modules described in Part 3 of this series: Schema Awareness, Backwards Compatibility, and Serialization. Another property that might be interesting is xsl:product-name, which can exclude large amounts of code based on which vendor's processor is running.

In use-when tests, the system-property() function is usually the best function to use, because its test is readable. The use-when filtering occurs early in the setup of a transformation, specifically before any input document is loaded or any launch options are acted upon. (See Part 3 for an explanation of launch options.) The system-property() function reports directly on the capabilities of the processor.


Summary

In the ideal world, a stylesheet is portable across processors yet able to exploit vendor-specific extensions and optimizations when run by a given vendor's processor. This is accomplished through namespaces. (See Resources to learn more about XML namespaces.) Several vendors might choose to implement a shared extension package such as EXSLT, in its own namespace, as well as their own extensions. Thus a processor might recognize several namespaces as designating elements (or attributes or functions) that it knows. Other foreign declarations and attributes must be ignored. Foreign instructions would raise an error if actually invoked, but you can guard against unwanted invocation using techniques described in this article. Given all these policies about treatment of unknown elements, Forwards Compatibility simply emerges as a special case that is accorded the same treatment.

The Working Group is strongly suggesting that @use-when is the way to make your stylesheets adaptable and configured appropriately for different platforms. It can adapt to anything that system-property() or function-available() tells you, it can exclude any element, and its exclusions happen at an early stage of processing.

You have now seen all the functions, instructions, and attributes that are used for compatibility across XSLT versions. This toolkit is slightly larger than the toolkit for portability across different implementations of the same XSLT version from different vendors. If you want to use 2.0 features and haven't started to look at your existing stylesheets and how they must change, this article provides some ideas about new code replacing old at different granularities. You might replace an XPath expression, an instruction, a template, or an imported stylesheet module, among other constructs, and the replacement might be a different granularity. For example, a new 2.0 function might allow a template with several expressions and instructions to collapse down to a single XPath 2.0 expression. The next article in this series will provide examples of the portability techniques in use. Together with this article, you will get a sense of the hands-on work that is needed to take advantage of the new features.


Appendix: Structure of a stylesheet

This article uses terms such as instructions, declarations, and extension elements to classify the elements and attributes of a stylesheet more precisely. These terms are needed to express the constraints on each item in the portability toolkit.

Categories of elements in a stylesheet

The XSLT 2.0 document issued by the W3C (see Resources) specifies 49 elements in the XSLT namespace, including 14 new ones, and provides guidance about non-XSLT elements that might be present. The XSLT processor that executes a stylesheet must recognize and enforce the XSLT namespace, and it can also recognize elements from other namespaces as meaningful. To ease the discussion of the roles of various elements that can appear in a stylesheet, they are classified by the depth at which they first appear.


Table 2. Structure of a stylesheet
LevelXSLT elements (some appear at more than one level)non-XSLT elements

0

xsl:stylesheet, xsl:transform

A non-XSLT element in an XML document can contain XSLT elements. This is the realm of the "embedded stylesheet" and outside the scope of this article.

1

Classic declarations that do not directly contain instructions and are used in the setup stages: xsl:character-map, xsl:decimal-format, xsl:import, xsl:import-schema, xsl:include, xsl:namespace-alias, xsl:output, xsl:preserve-space, xsl:strip-space (most don't contain sub-elements)

Definition-type declarations that can contain instructions: xsl:attribute-set, xsl:function, xsl:key, xsl:param, xsl:template, xsl:variable

User-Defined Data Element (UDDE) or extension declaration (processor decides, based on namespace)

Note: Elements whose name is not namespace-qualified raise an error.

2

Instructions: xsl:analyze-string, xsl:apply-imports, xsl:apply-templates, xsl:attribute, xsl:call-template, xsl:choose, xsl:comment, xsl:copy, xsl:copy-of, xsl:document, xsl:element, xsl:fallback, xsl:for-each, xsl:for-each-group, xsl:if, xsl:message, xsl:namespace, xsl:next-match, xsl:number, xsl:perform-sort, xsl:processing-instruction, xsl:result-document, xsl:sequence, xsl:text, xsl:value-of, xsl:variable

Literal Result Element (LRE), unless its namespace has been declared to be an extension namespace, in which case it is an extension instruction.

subsidiary

Subsidiaries to specific instructions: xsl:matching-substring, xsl:non-matching-substring, xsl:otherwise, xsl:sort, xsl:when, xsl:with-param

Subsidiaries to declarations: xsl:attribute, xsl:output-character, xsl:param

Treatment of non-XSLT elements depends on the constraints of the containing element. For example, xsl:choose does not allow any subsidiaries other than xsl:when and xsl:otherwise, regardless of namespace or lack thereof.

Notes about Declarations and UDDEs

The elements at level 1 were called top-level elements in the XSLT 1.0 document. The ones in the XSLT namespace are called declarations in the XSLT 2.0 document. Other namespace-qualified elements at level 1 of the stylesheet are called user-defined data elements (UDDEs) in the XSLT 2.0 document. Fallback does not work on declarations or UDDEs.

UDDEs must be ignored if not recognized by the processor. A processor might recognize UDDEs in its own namespace for various uses; the XSLT 1.0 spec suggested optimization hints, information about handling inputs and outputs, structured documentation of the stylesheet, and declarations associated with extension elements or functions from the same namespace. The 1.0 spec overlooked the potential of foreign elements belonging to the stylesheet writer rather than the processor vendor and being used for in-stylesheet data, especially a table for xsl:key. The new name (UDDE) suggests that the XSL Working Group now recognizes data storage as the most likely use. UDDEs may support the standard attributes or allow XSLT instructions as children, at the discretion of the vendor implementing the processor. In any case, UDDEs must not alter conformant processing.

When a vendor implements the Schema Awareness feature module (see Parts 1 and 3 of this series), the XSLT processor will accept the xsl:import-schema declaration. This element is different from the others; instead of XSLT elements, it has elements of the XML Schema vocabulary as its (optional) children.

Notes about Instructions and LREs

The elements at level 2 are called instructions in both versions of XSLT. Level 2 is also where Literal Result Elements (LREs) occur, which are elements that are to be replicated in the result rather than serving as instructions to the processor. The 2.0 spec has a formal definition of instruction and of the sequence constructor that comprises a series of instructions and LREs. (Sequence constructors can also contain character data, either between elements or alone.) Some XSLT elements contain a sequence constructor, as can an LRE. The sequence constructors of some XSLT elements are restricted; for example, the sequence constructor of xsl:comment cannot contain any instructions that would cause the comment content to be anything other than text.

The extension-element-prefixesstandard attribute is significant for all prefixes, even for ones not recognized by the processor currently executing the stylesheet (that is, other vendors' extensions). It separates LREs from foreign elements that should be treated as instructions rather than LREs. While a processor does not need extension-element-prefixes to recognize extension attributes, UDDEs serving as extension declarations, and extension functions, it is always a good idea to make the explicit statement, and it will also suppress the creation of a namespace declaration for that prefix in the result document.

Extension instructions can support the standard attributes or allow XSLT instructions as children, at the discretion of the vendor implementing the processor. Even support for @use-when is discretionary. Extension instructions must allow xsl:fallback as a child element.

Subsidiary XSLT elements

The last row of the structure table (Table 2) lists those elements that occur as subsidiaries to particular instruction or declaration elements. The Working Group that wrote the specs has not bothered to provide a term for these. Some, like xsl:when, are only permitted as a child of one specific element. All subsidiaries can contain a sequence constructor except xsl:output-character and xsl:param when it is a subsidiary of xsl:function.

Notes about Attributes

In both 1.0 and 2.0, non-namespaced attributes that appear on an XSLT element, other than the specified ones, cause an error unless FC mode is in effect. This is especially significant for use-when, which was unknown in 1.0 and is a standard attribute in 2.0. Since XSLT stylesheets are XML documents, XSLT elements are also allowed to have attributes in the xml and xmlns namespaces.

An attribute from another namespace can appear on an XSLT element; it is ignored unless its namespace is treated by the processor as an extension namespace and the vendor has ascribed a particular significance to that attribute, in which case it is an extension attribute (now an official term in the specs). In 1.0, extension attributes were often used in xsl:output to provide extra control over serialization. There is no requirement to declare explicitly that attributes in a particular namespace are extension attributes, which is why XSLT is so tolerant of attributes it doesn't recognize.

A namespaced attribute on an LRE must always be copied through to the result, except for those in the XSLT namespace. If the attribute is recognized by the processor as an extension attribute that the processor implements, then the attribute may affect the behavior of the processor (within limits) as well as being copied.

Non-XSLT constructs found in a stylesheet

The structure table shows how the processor must handle foreign elements at each level. XSLT is extensible, and it has been designed to tolerate foreign attributes on any element. On the other hand, an XSLT processor is not allowed to recognize extension points in any comment or text node of the stylesheet. The XML namespaces mechanism (see Resources for links) is used to keep one processor's extension elements, attributes, and functions separate from those of another processor, as well as from the official XSLT constructs.


Resources

Learn

Get products and technologies

  • IBM trial software: Build your next development project with trial software available for download directly from developerWorks.

Discuss

About the authors

David Marston has worked with XML technologies since late 1998, particularly on standards conformance. Over his 25+ years in the computing business, he has been involved with all aspects of software development. He is a graduate of Dartmouth College and a member of the ACM. He is on the Next-Generation Web team at IBM Research. You can contact him at David_Marston@us.ibm.com.

Joanne Tong is a developer working on IBM's XSLT processors in the IBM Toronto lab. She is currently an editor of the W3C XSLT 2.0 and XQuery 1.0 Serialization specification and is an active member of the XSL working group. You can contact her at joannet@ca.ibm.com.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in

If you don't have an IBM ID and password, register here.


Forgot your IBM ID?


Forgot your password?
Change your password


By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. This profile includes the first name, last name, and display name you identified when you registered with developerWorks. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)


By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=XML
ArticleID=196638
ArticleTitle=Planning to upgrade XSLT 1.0 to 2.0, Part 4: The toolkit for XSLT portability
publish-date=02202007
author1-email=David_Marston@us.ibm.com
author1-email-cc=dwxed@us.ibm.com
author2-email=joannet@ca.ibm.com
author2-email-cc=dwxed@us.ibm.com

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

For articles in technology zones (such as Java technology, Linux, Open source, XML), Popular tags shows the top tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), Popular tags shows the top tags for just that product zone.

For articles in technology zones (such as Java technology, Linux, Open source, XML), My tags shows your tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), My tags shows your tags for just that product zone.

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).