XSLT 在保证跨平台和处理器的互操作性方面确实做得很好。把样式表移植到新的处理器通常只需要复制文件就可以了。但是有时候仍然需要针对给定的处理器放弃一些可移植性并调整样式表。这篇技巧说明如何测试所运行的平台并相应地调整代码。
为何要放弃可移植性呢?一个原因可能是由于需要使用 XSLT 1.0 不支持的函数——比如向多文档输出或者创建中间结果树的能力。对于给定的处理器,工作方式总是特殊的。
另外一个原因可能是由于需要做一些特定于平台的事情。比如,我最近编写了一个处理文件名的样式表。因为文件分隔符对于每种平台都是惟一的(所有的
UNIX 变体都使用 "
/ ",Windows 下是 "
\ ",而 MacOS 标准是 "
: "),所以样式表只能针对具体平台。
无论什么原因,最好是把特定于平台的代码隔离在一个模板、变量或者参数中,以便容易移植到其他的平台。理想的方案是测试样式表中使用的是何种处理器并切换到相应的代码段。测试平台需要使用
system-property() 函数。
顾名思义,
system-property() 返回特定于系统的属性值。XSLT 标准定义了以下三个属性:
-
xsl:version:处理器所支持的 XSL 版本(目前是 1.0) -
xsl:vendor:处理器的供应商 -
xsl:vendor-url:用于确定处理器供应商的 URL
处理器供应商完全可以识别更多的属性。多数 Java 处理器还返回 Java 系统属性,其中包括:
-
java.version:所使用的 JVM 版本 -
java.vendor:JVM 制造商 -
os.name:所使用的 OS -
file.separator:依赖于系统的文件分隔符
还定义了许多其他的属性,完整的属性列表请参阅 参考资料。
清单 1 给出了
system-property() 的一个应用程序。样式表通过查询
xsl:vendor
和其他属性试图猜测系统所用的文件分隔符。样式表在
file-separator 参数中保存结果。逻辑如下:
- 如果供应商是 Microsoft 或 Altova (二者都是众所周知的 Windows 处理器),则假定为 Windows 系统的分隔符(
/)。 - 如果处理器接受 Java 属性,则查询
file.separator属性。该属性对多数 Java 处理器都是有效的,如 Xalan 或 Saxon。 - 如果处理器是 XT,则使用所有权扩展机制检索
file.separator属性的值。 - 如果所有的测试都失败,则停止。
<?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>
|
理想情况下永远不需要特定于处理器的代码,但我们不是生活在一个完美的世界。次佳的方案是把特定于处理器的代码隔离在一个变量、参数或者模板中。当把样式表移植到不同的处理器时使用
system-property() 。
- 您可以参阅本文在 developerWorks 全球站点上的
英文原文.
- 参与 Benoit Marchal“使用 XML”专栏的
讨论论坛。
- 请阅读 Uche Ogbuji 所写的“
多步骤 XSLT”一文 (
developerWorks,2002
年 9 月),了解如何通过 XSL 扩展创建中间结果树。
- 请阅读 Benoit Marchal 的技巧文章“
对大型 XML 文档分而治之” (
developerWorks,2003
年 6 月),了解另外一个用于多重输出的特定于处理器的扩展。
- 在
JDK
1.4.2 API documentation中查看 Java 技术的标准系统属性。
Xalan
和
Saxon
(还有其他一些处理器)能够识别这些属性。
- 在
XT
documenttation中学习 XT 扩展的用法以检索 Java 对象。
- 在
developerWorks
XML
专区上查找更多 XML 资源。关于最新 XML 技巧的全部列表,请访问
实用技巧。
- 了解如何成为一名
IBM
认证的 XML 及相关技术的开发人员。

Benoit Marchal是一位比利时籍顾问。他是 XML by Example, Second Edition 和其他 XML 书籍的作者。可以向 Benoit 寻求有关 XML 项目的帮助——可以通过 bmarchal@pineapplesoft.com 或他的个人站点 marchal.com 与他联系。