浏览器中的XSLT支持

来源:互联网 发布:网页cc源码 编辑:程序博客网 时间:2024/05/30 23:08

XML的姊妹语言——XSLT(可扩展样式表语言转换)可以对XML进行操作,将其转换成任何基于文本的形式。目前,很多开发人员都用XSLTXML转换成HTML,当然,这只是其中一种用途(见图15-1)。

其他

 

格式

 

图 15-1

XSLT文件称为样式表,由一些模板组成。模板属于XML的某个特性的一部分(使用XPath指定),它可以决定为这一部分输出什么文本。通过为不同的元素和条件定义模板,XSLT样式表变成了一种XML 解析器。例如,考虑前面用过的XML

现在假设你想将这个雇员列表按照以下的HTML格式显示:

其实,就是从内容中拉出<name/>元素的内容,然后将其放入一个无序列表中。然如要将<employee/>title特性取出,并放在<em/>元素内的名字旁边,则可以创建一个XSLT样式表:

可以看到,XSLT其实就是另一个基于XML的语言。文档元素是<xsl:stylesheet/>,它还指定了XSLT使用的版本(1.0)以及命名空间URL。缺少这个信息,XSLT处理器则无法正确使用样式表。

下面一行包含<xsl:output/>元素,它指定了输出处理的规则。对于method特性,有三种可能的值:htmlxmltext。使用html时,解析器将输出作为HTML对待,也就是说不会应用严格的XML规则;xml强制对输出应用所有的XML规则,同时text只输出包含在元素之外的内容。

下面讨论模板。第一个模板匹配了文档元素,由match= "/".;制定;/ XPath表达式总是指向文档元素。在模板中还有HTML代码,直到<xsl:apply-templates/>元素,让解析器为子节点(这是匹配所有子节点的XPath表达式)应用任何匹配模板。因为已定义了匹配这个模式的模板,所以处理继续进行。

在第二个模板中,注意<li>元素。后面紧跟着<xsl:value-of/>元素,它用于从源XML中输出一个值。select特性是另一个XPath表达式——name,指示输出<name/>元素的值(包含其中的文本)。然后,是一个逗号,然后是起始<em>标签,后面是另一个<xsl:value-of/>元素。这次,select特性指向<employee/>title特性,这样转换器就输出了title特性值。

XSLT样式表应用于XML文件时,就可以出现前面的HTML结果。尽管例子很简单,不过还是显示了XSLT的一些独特能力。

如果想学习XSLT,请参阅XSLT 2.0: Programmer’s Reference, 3rd EditionWiley 出版社ISBN 0-7645-6909-0)。

15.3.1  IE中的XSLT支持

MSXML 3.0开始,IE就完全支持XSLT 1.0了。如果你还在使用IE 5.0或者5.5,必须手工安装新版的MSXML;如果在使用IE 6.0,那么就表示你至少已经有了MSXML 3.0

最简单的进行XSLT转换的方法是,分别将XML源代码和XSLT文件载入各自的DOM,并使用特有的transformNode()方法:

这个例子中的一个DOM载入了XML,而另一个DOM载入了XSLT样式表(注意XSLT也可以载入XML DOM因为它也是一种XML格式)。然后,第三行调用文档的transformNode()方法,并将包含XSLT代码的DOM作为唯一的参数传给它。然后在变量sResult中放入转换后的文本结果。

你无需从文档层次开始转换;每一个节点都有个transformNode()方法。下面的均有效:

如果在非文档元素中调用transformNode(),则从这个点开始转换,但是XSLT样式表能访问包含这个节点的整个XML文档。

IE中使用XSLT的另外一个比较复杂的方法是,使用XSL模板和处理器。这种方法必须使用MSXML的其他几个ActiveX控件。首先,XSLT文件必须载入到一个自由线程DOM文档中(行为和普通DOM一样,但是线程是安全的)。

自由线程DOM文档建立并加载好后,必须将其分配到XSL模板中,这是另一个ActiveX对象:

然后,可以用XSL模板来创建一个XSL处理器(当然也是另一个ActiveX对象):

创建处理器后,将input特性设置为要进行转换的XML DOM节点,然后调用transform()方法:

然后从output特性中访问结果字符串:

这些代码模仿了transformNode()的功能。你肯定在想,如果两种方法都一样,为什么会有人使用XSL模板/处理器的方法。答案是处理器允许你更多地控制XSLT

例如,XSLT样式表可以接受传入的参数,并将其用作局部变量。考虑下面的样式表:

这个样式表添加了两行代码。第一行是<xsl:param/>元素,它定义了message的参数。第二行通过<xsl:value-of/>元素输出message(美元符号表示这个是局部变量,而不是特性)。

要设置message的值,可在调用transform()前使用addParameter()方法。AddParameter ()方法有两个参数,要设置的参数的名称(与<xsl:param/>中指定的一样)以及分配给它的值(一般是字符串,不过也可以是数字或者是布尔值):

为参数设置一个值后,输出就变成这样了:

可以看到,通过JavaScript传入的值正确地输出了HTML结果。这样,就可以通过加入基于参数的不同行为使样式表更加有弹性。

另一个XSL处理器的高级特性是,设置操作的模式的能力。在XSLT中,可以定义模板的模式。定义mode后,除非<xsl:apply-template />指定按照mode特性进行调用,否则模板不会运行。例如:

这个样式表定义了mode特性为"position-first"的模板(注意可以任意地命名;无任何预定义的模式)。在这个模板中,首先输出雇员的位置,然后输出雇员的名称。为使用这个模板,<xsl:apply-templates/>元素必须也将其mode设置为"position-first"。如果使用这个样式表,它的输出也与前面一样,首先显示雇员名称,然后显示位置。但是,如果用这个样式表,并使用JavaScript将模式设置为"position-first",则先输出雇员的位置:

setStartMode()方法只接受一个参数,要设置的模式。与addParameter()一样,必须在transform()之前调用.

如果要使用同一个样式表进行多次转换,则可在每次转换后重置处理器。调用reset()方法,输入和输出特性则会被清除,处理器又可以使用了。

因为处理器已经编译过XSLT样式表,这要比重复调用transformNode()快得多。

MSXML只支持XSLT 1.0MSXML的开发自从转到.NET Framework后就停止了。可能,在未来的某天,JavaScript会允许访问XMLXSL.NET对象。

15.3.2  MozillaXSLT支持

Mozilla 1.2开始,JavaScript开发人员就可用XSLTProcessor对象来进行客户端的XSLT转换了。这个对象使用Mozilla内置的XSLT处理器——Transformiix

转换过程的第一步是将XMLXSLT载入DOM

然后,创建XSLTProcessor并使用importStylesheet()方法来分配XSLT DOM

最后一步是调用transformToDocument()或者transformToFragment(),并以XML DOM为参数,最后返回结果。transformToDocument()返回的是新的DOM文档,transformTo Fragement()返回新的文档碎片,一般来说,应该使用transformToDocument()除非你想直接将结果添加到某个已经存在的文档中,后一种情况才使用transformToFragement()

使用transformToFragment(),仅传入XML DOM并将结果作为另一个完整不同的DOM

使用transformToFragment(),传入XML DOM和要添加到结果的文档。这确保了新的文档碎片在目标文档中是有效的。

在前面的例子中,处理器创建了由document对象所有的碎片。这使得碎片添加到了页面中的<div/>元素中。

XSLT的输出方法是HTML或者XML时,这些当然很有意义,但如果输出的是文本方式呢?要解决这个问题,Mozilla创建了单个元素的XML文档<transformiix:result/>,包含了所有输出的文本。所以,从XSLT文件中使用文本输出也产生有效的文档或者文档碎片。

记住这一点,就可为Mozilla创建transformNode()方法了:

这个方法是用给定的XML DOM创建结果文档。然后使用xml特性(本章前面定义的)将结果XML代码存储到sResult。然后检查代码是否包含<transformiix:result/>。如果有,则XML部分被去除(只要取出第一个大于号和最后一个小于号之间的文本)。最后,返回sResult。用这个方法,你可以创建在MozillaIE中都能使用的代码:

也可以为Mozilla中的XSLTProcessor设置XSLT参数。setParameter()方法接受三个参数:命名空间URI,参数本地名称及要设置的值。一般来说,命名空间URInull,本地名称就是参数的名称,这个方法必须在transformToDocument()或者transformToFragment()方法之前调用。

还有另外两个方法与参数有关,getParameter()removeParameter(),分别用于获取某个参数当前的值和删除参数值。它们都以一个命名空间URI(也可以为null)和参数的本地名称为参数:

这些方法不常用,主要是为了方便才提供的。