XSLT does a decent job of ensuring interoperability between platforms and processors. Porting a stylesheet to a new processor is typically as simple as copying the file. Still, at times, you need to forgo some portability and adapt your stylesheets to a given processor. This tip shows you how to test the platform you're running on and adapt your code accordingly.
How portable do you want to be?
Why forgo portability? One reason might be because you need a function that XSLT 1.0 does not support -- for example, the ability to output to multiple documents or to create an intermediate result tree. The workarounds are always specific to a given processor.
Another reason might be because you're doing something that is platform-specific. For example, I recently wrote a stylesheet for processing filenames. Since the file separator is unique to each platform ("/" for all UNIX variants, "\" under Windows, and ":" for MacOS classic), the stylesheet has to be platform-specific.
Whatever the reason, it is best to isolate the platform-specific code in a template, a variable, or a parameter so it's easy to port to another platform. The ideal solution is to test which processor you're using in the stylesheet and branch to the appropriate code section. To test the platform, you would use the system-property() function.
As the name implies, system-property() returns the value of system-specific properties. The XSLT standard defines the following three properties:
-
xsl:version: XSL version supported by the processor (currently 1.0) -
xsl:vendor: the processor vendor -
xsl:vendor-url: a URL identifying the processor vendor
Processor vendors are free to recognize more properties. Most Java processors also return Java system properties, which include the following:
-
java.version: version of the JVM you're running on -
java.vendor: JVM manufacturer -
os.name: OS you're running on -
file.separator: system-dependent file separator
Many more properties are defined -- see the complete list in Resources.
Listing 1 demonstrates one application of system-property(). The stylesheet attempts to guess the file separator for your system by querying xsl:vendor and other properties. The stylesheet stores the result in the file-separator parameter. The logic is as follows:
- If the vendor is Microsoft or Altova (both well-known Windows processors), assume the Windows system separator (
/). - If the processor accepts Java properties, query the
file.separatorproperty. This works with most Java processors such as Xalan or Saxon. - If the processor is XT, use a proprietary extension mechanism to retrieve
the value of the
file.separatorproperty. - If all tests fail, terminate.
Listing 1. A stylesheet that tests its environment
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xm="http://www.ananas.org/2001/XM/Walk/Directory"
version="1.0">
<xsl:output method="html"/>
<xsl:param name="file-separator">
<xsl:variable name="vendor"
select="system-property('xsl:vendor')"/>
<xsl:choose>
<!-- two well-known XSLT processors for Windows -->
<xsl:when test="contains($vendor,'Microsoft')
or contains($vendor,'Altova')">
<xsl:text>\</xsl:text>
</xsl:when>
<!-- the processor returns Java properties -->
<xsl:when
test="string-length(system-property('java.version')) != 0">
<xsl:value-of select="system-property('file.separator')"/>
</xsl:when>
<!-- the processor is XT, use an extension -->
<xsl:when test="contains($vendor,'James Clark') and
function-available('xt-sys:getProperty')"
xmlns:xt-sys="http://www.jclark.com/xt/java/java.lang.System">
<xsl:value-of select="xt-sys:getProperty('file.separator')"/>
</xsl:when>
<xsl:otherwise>
<xsl:message terminate="yes">unknown file separator</xsl:message>
</xsl:otherwise>
</xsl:choose>
</xsl:param>
<xsl:template match="xm:Directory">
<html>
<head><title>File list</title></head>
<body><ul><xsl:apply-templates/></ul></body>
</html>
</xsl:template>
<xsl:template match="xm:File">
<li><a href="file:{.}">
<xsl:call-template name="extract-fname">
<xsl:with-param name="path" select="."/>
</xsl:call-template>
</a></li>
</xsl:template>
<xsl:template name="extract-fname">
<xsl:param name="path"/>
<xsl:choose>
<xsl:when test="contains($path,$file-separator)">
<xsl:call-template name="extract-fname">
<xsl:with-param name="path"
select="substring-after($path,$file-separator)"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$path"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet> |
Ideally you would never need processor-specific code, but we don't live in a perfect world. The next best solution is to isolate the processor-specific code in a variable, a parameter, or a template. Use the system-property() as you port your stylesheet to different processors.
- Participate in the discussion forum for Benoit Marchal's Working XML column.
- Learn how to create an intermediate result tree through XSL extensions with
"Multi-pass
XSLT" (developerWorks, September 2002) by Uche Ogbuji.
- Take a look at another processor-specific extension for multiple output in Benoit
Marchal's tip "Divide
and conquer large documents" (developerWorks, June
2003).
- Find the standard system properties for Java technology in the JDK
1.4.2 API documentation. Xalan and Saxon (amongst others) recognize those properties.
- Read about the use of XT extensions to retrieve Java objects in
the XT
documentation.
- Find more XML resources on the developerWorks
XML zone. For a complete list of XML tips to date, check out the tips summary page.
- Learn how you can become an IBM Certified Developer in XML and related technologies.

Benoit Marchal is a Belgian consultant. He is the author of XML by Example, Second Edition and other XML books. Benoit is available to help you with XML projects. You can contact him at bmarchal@pineapplesoft.com or through his personal site at marchal.com.
Comments (Undergoing maintenance)





