Xalan支持使用Javascript及其他script语言扩展XSLT。由于其他语言例如NetRexx,BML,JPython,Jacl在国内应用不多,因此就不进行介绍了。而VBScript由于仅仅应用于Microsoft平台,因此也不进行介绍。对于perl扩展本文将少量的介绍。使用这些语言进行扩展需要使用由IBM提供的Bean Script Framework(BSF),使用Javascript扩展XSLT还需要安装Mozilla.org提供的javascript解释器Rhino。具体设置方法就是将js.jar文件设置进classpath。
由于XSLT本身提供的方法有限,因此有的时候我们需要自己编写函数进行扩展,另外,对于经常使用的扩展,apache-Xalan提供了一个扩展库,大家可以直接使用。
下面我们就开始介绍如何扩展XSL。在扩展XSL的时候我们可以扩展两种东西,第一是element第二是function。对于element的扩展我们可以理解为增加了具有新的功能的xslt元素。但是同基本的xslt元素不同的是,扩展元素可以进行扩展元素可以进行很多在xsl文件中没有表现出来的工作。实际上,我们在扩展element的时候实际上是定义了一个和这个element同名的函数。对于function的扩展我们可以理解为对xpath提供的函数的扩展。但是我们要在自己的名空间里面使用这些函数。扩展XSL基本可以分五步完成。
第一步是设定Xalan所使用的名空间。例如我们可以在xsl文件中通过下面的语句来完成上面的工作。<xsl:stylesheet xmlns:lxslt="http://xml.apache.org/xslt"/>。这里名空间的名字可以使用任意的名字但是url必须使用http://xml.apache.org/xslt,因为只有这样,xalan才能够识别出来它所使用的名空间。为了使用方便,我们在以后都将使用lxslt这个名字。
第二步是设定扩展所使用的名空间。我们可以通过下面的语句来完成。<xsl:stylesheet xmlns:my-ext"ext1"/>。这里可以使用任意的名字。
第三步是把扩展所使用的名空间设定为extension-element-prefixes。我们可以通过一下的xml代码完成。<xsl:stylesheet extension-element-prefixes="my-ext"/>。主意!上面所有的命令在真正使用的时候是要写道一个标签里面的。
第四步是用script写扩展元素与扩展方法。这一步有一些小小的技巧。我们需要仔细来讨论。首先我们来讨论如何把这些代码包含在一个tag里面。这里我们要使用如下的tag。
&lt;lxslt:component prefix=&quot;prefix&quot; functions=&quot;func-1 func-2 ...func-n&quot; elements=&quot;elem-1 elem-2 ...elem-n&quot;&gt; &lt;/lxslt:component&gt;
这里func-1等等是方法的名字,elem-1等等是扩展元素的名字。而在这个tag里面,我们又要包含一个tag书写真正的javascript代码。这个tag的使用如下面的例子。
&lt;lxslt:script lang=&quot;javascript&quot; &gt; &lt;!--The implementation script--&gt; &lt;/lxslt:script&gt;
下面我们就开始讨论如何具体写扩展element和扩展function。首先我们来看看怎么写扩展element。在写一个扩展element之前,我们要在component标签中声明这个element。然后我们可以在script标签中定义一个和我们要扩展的element同名的javascript方法。这里借用了C语言中的声明和定义的概念,希望大家能够懂。例如我们又如下的xml文件,
&lt;?xml version=&quot;1.0&quot;?&gt; &lt;person sex=&quot;m&quot;&gt;Bean&lt;/person&gt;
我们要定义一个很无聊的标签,叫做out的,这个标签里除了完成标签内部所有的xsl命令之外还在最后加上一句"吃了吗"。呵呵,这个标签应该是无聊道极点了,但是应该能够让大家看懂是怎么回事。定义这个element的code如下。
&lt;lxslt:component prefix=&quot;my-ext&quot; elements=&quot;out&quot; functions=&quot;displaySex&quot;&gt; &lt;lxslt:script lang=&quot;javascript&quot;&gt; function out(xslProcessorContext, elem){ var o = elem.getChildNodes(); var oTransformer = xslProcessorContext.getTransformer(); try{ for(var i = 0 ; i &amp;lt; o.getLength() ; i ++ ){ o.item(i).execute( oTransformer ); } }catch( e ){ return e; } return &quot;,吃了吗?&quot;; } &lt;/lxslt:script&gt; &lt;/lxslt:component&gt;
在这里面我们看到定义了一个叫做out的方法,然后这里面又两个参数,其原型分别是org.apache.xalan.extensions.XSLProcessorContext和org.apache.xalan.templates.ElemExtensionCall。大家可以参考他们的javadoc文档,这里就不进行介绍了。函数内部的实现也很简单,我认为大家如果从aelfred学习道这里掌握这些东西是没有什么问题的。下面我们介绍关于定义一个扩展方法的知识。
扩展方法同扩展element的定义方法差不多,只是没有了必须要定义的参数,而且参数由自己来控制。例如我们下面定义的方法可以从参数获取性别,然后返回适当的称呼。
&lt;lxslt:component prefix=&quot;my-ext&quot; elements=&quot;out&quot; functions=&quot;displaySex&quot;&gt; &lt;lxslt:script lang=&quot;javascript&quot;&gt; function out(xslProcessorContext, elem){ var o = elem.getChildNodes(); var oTransformer = xslProcessorContext.getTransformer(); try{ for(var i = 0 ; i &amp;lt; o.getLength() ; i ++ ){ o.item(i).execute( oTransformer ); } }catch( e ){ return e; } return &quot;,吃了吗?&quot;; } function displaySex( sex ){ var sexStr = new String(sex.item(0).getNodeValue()); if( &quot;m&quot; == sexStr ) return &quot;先生&quot;; else if( &quot;f&quot; ==sexStr ) return &quot;女士&quot;; else return new String(sex.item(0).getNodeValue()); } &lt;/lxslt:script&gt; &lt;/lxslt:component&gt;
第五步是在xsl文件中调用扩展方法。相对于上面的内容,调用就简单的多了。下面的代码给出了如何调用。
&lt;xsl:template match=&quot;person&quot;&gt; &lt;result&gt;&lt;my-ext:out&gt;&lt;xsl:value-of select=&quot;.&quot;/&gt;&lt;xsl:value-of select=&quot;my-ext:displaySex(@sex)&quot;/&gt;你好&lt;/my-ext:out&gt;&lt;/result&gt; &lt;/xsl:template&gt;
下面我们给出完整的xsl文件。
&lt;?xml version=&quot;1.0&quot; encoding=&quot;GB2312&quot;?&gt; &lt;xsl:stylesheet xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot; version=&quot;1.0&quot; xmlns:lxslt=&quot;http://xml.apache.org/xslt&quot; xmlns:my-ext=&quot;ext1&quot; extension-element-prefixes=&quot;my-ext&quot;&gt; &lt;xsl:output encoding=&quot;GB2312&quot;/&gt; &lt;lxslt:component prefix=&quot;my-ext&quot; elements=&quot;out&quot; functions=&quot;displaySex&quot;&gt; &lt;lxslt:script lang=&quot;javascript&quot;&gt; function out(xslProcessorContext, elem){ var o = elem.getChildNodes(); var oTransformer = xslProcessorContext.getTransformer(); try{ for(var i = 0 ; i &amp;lt; o.getLength() ; i ++ ){ o.item(i).execute( oTransformer ); } }catch( e ){ return e; } return &quot;,吃了吗?&quot;; } function displaySex( sex ){ var sexStr = new String(sex.item(0).getNodeValue()); if( &quot;m&quot; == sexStr ) return &quot;先生&quot;; else if( &quot;f&quot; ==sexStr ) return &quot;女士&quot;; else return new String(sex.item(0).getNodeValue()); } &lt;/lxslt:script&gt; &lt;/lxslt:component&gt; &lt;xsl:template match=&quot;person&quot;&gt; &lt;result&gt;&lt;my-ext:out&gt;&lt;xsl:value-of select=&quot;.&quot;/&gt;&lt;xsl:value-of select=&quot;my-ext:displaySex(@sex)&quot;/&gt;你好&lt;/my-ext:out&gt;&lt;/result&gt; &lt;/xsl:template&gt; &lt;/xsl:stylesheet&gt;