IE中有两种方法来完成XML文档的转换,这两种方法都必需使用MSXML。从MSXML 3.0版开始,MSXML对XSLT1.0提供完整的支持。如果没有Windows XP或IE 6,那么应当升级。你可以在http://msdn.microsoft.com/XML/XMLDownloads/中找到并下载最新的MSXML。
首先,使用最简单的方法将XML和XSLT文档载入到各自的XML DOM对象中:
var oXmlDom = zXmlDom.createDocument();
var oXslDom = zXmlDom.createDocument();
oXmlDom.async = false;
oXslDom.async = false;
oXmlDom.load(“books.xml”);
oXslDom.load(“books.xsl”);
当载入文档后,就可以调用transformNode()方法进行转换:
var sResults = oXmlDom.transformNode(oXslDom);
transformNode()方法的参数为XML DOM对象(本示例为XSL文档),并以字符串形式返回转换后的数据。但是不一定要在文档对象处调用transformNode()方法,也可以在XML文档的任何元素处调用该方法:
var sResults = oXmlDom.documentElement.firstChild.transformNode(oXslDom);
transformNode()方法只会从调用的元素开始转换该元素及其子元素。示例中转换了第一个<book/>元素,如图4-3所示。这是因为对没有子元素的元素调用transformNode()方法只会转换一个节点。

图 4-3
IE中第二个转换方法稍微有些复杂,但提供更多的控制权和特性。该过程需要创建多个MSXML库中的对象。这个稍长过程的第一步是创建一个线程安全的XML DOM对象,并将XSL样式表载入该对象:
var oXmlDom = zXmlDom.createDocument();
oXmlDom.async = false;
oXmlDom.load("books.xml");
var oXslDom = new ActiveXObject("Msxml2.FreeThreadedDOMDocument.3.0");
oXslDom.async = false;
oXslDom.load("books.xsl");
FreeThreadedDOMDocument类是另一个ActiveX类,且是MSXML库中的一部分。必须使用FreeThreadedDOMDocument类来创建XSLTemplate对象,如该示例所示(下一个示例将显示XSLTemplate对象的创建)。在MSXML的早期版本中,对每个transformNode()方法的调用都需要对XSL样式表进行重新编译,这在一定程度上会降低了转换的速度。如果基于FreeThreadedDOMDocument,编译后的样式表会放入缓存供以后使用,直到从内存中移出。
XML DOM对象创建后,还需要创建另一个ActiveX对象,即XSL模板对象:
var oXslTemplate = new ActiveXObject("Msxml2.XSLTemplate.3.0");
oXslTemplate.stylesheet = oXslDom;
XSLTemplate类用于缓存XSL样式表并创建XSLProcessor,所以当模板创建后,XSL文档赋值给XSLTemplate类的stylesheet属性,实现缓存功能并载入XSL样式表。
该过程的下一步是创建XSLProcessor,通过调用XSLTemplate类的createProcessor()方法创建:
var oXslProcessor = oXslTemplate.createProcessor();
oXslProcessor.input = oXmlDom;
创建处理器后,其input属性将赋值为oXmlDom,也就是包含待转换XML文档的XML DOM对象。现在,处理器所需一切都准备就绪,所以余下工作就是实际的转换和获取输出:
oXslProcessor.transform();
document.body.innerHTML = oXslProcessor.output;
与transformNode()不一样,transform()方法并不以字符串形式返回结果。为了得到转换的输出,需要使用XSLProcessor对象的output属性。其整个过程比transformNode()方法需要更多的代码,并得到相同的结果。为什么要使用这样的过程呢?
MSXML提供一些额外的可以用于转换的方法。第一个方法是addObject()。该方法往样式表中添加一个JavaScript对象,可以在转换后的文档中调用方法和output属性值。考虑下面的对象:
var oBook = {
propertyOne : "My Current Books",
methodOne : function () {
alert("Welcome to my Book List");
return "";
}
};
如果想要在转换中使用该信息,该怎么样呢?使用addObject()方法,就可以将该信息传到XSLT样式表,这里需要传入两个参数:oBook对象和命名空间URI。所以,要将"http:// my-object"的命名空间URI添加到该对象,可以按下述代码所示的方法来完成:
var oXmlDom = zXmlDom.createDocument();
oXmlDom.async = false;
oXmlDom.load("books.xml");
var oXslDom = new ActiveXObject("Msxml2.FreeThreadedDOMDocument.3.0");
oXslDom.async = false;
oXslDom.load("books.xsl");
var oXslTemplate = new ActiveXObject("Msxml2.XSLTemplate.3.0");
oXslTemplate.stylesheet = oXslDom;
var oXslProcessor = oXslTemplate.createProcessor();
oXslProcessor.input = oXmlDom;
oXslProcessor.addObject(oBook, "http://my-object");
oXslProcessor.transform();
document.body.innerHTML = oXslProcessor.output;
oBook对象将传到XSLProcessor中,意味着XSLT样式表可以使用该对象。现在必须对XSL文档进行修改,才能够查找该对象并使用其信息。第一件事是添加新的命名空间到根元素<xsl:stylesheet/>中。该命名空间将匹配addObject()中的命名空间:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:bookObj="http://my-object">
前缀bookObj可以用来访问该信息。现在命名空间和前缀都准备好了,应当往文档中添加一些<xsl:value-of/>元素来获取对象成员:
<xsl:template match="/">
<html>
<head>
<link rel="stylesheet" type="text/css" href="books.css" />
</head>
<body>
<xsl:value-of select="bookObj:methodOne()" />
<div align="center">
<b><xsl:value-of select="bookObj:get-propertyOne()" /></b>
</div>
<xsl:apply-templates />
</body>
</html>
</xsl:template>
请记住,<xsl:value-of/>XSL指令获取元素或对象的值。第一个<xsl:value-of/>指令获取(或调用)methodOne(),该方法发送一个欢迎用户到该页面的信息。第二个<xsl:value-of/>指令与第一个非常相似,该指令获取oBook对象的propertyOne属性的值。当在浏览器中显示转换后的输出时,用户会在页面顶部看到“My Current Books”的字句。
当在转换中使用对象时,所有属性和方法都必须返回XSLProcessor能够理解的值:字符串、数字以及布尔值。返回其他值将会在执行转换时抛出JavaScript错误。
XSLProcessor另一个有用的特性是addParameter()方法。与将对象进行转换不同,该方法的参数是XSLT标准部分。参数传入XSL样式表,并可以作为变量使用。为了指定参数,并传入名称和值,如下所示:
var oXslProcessor = oXslTemplate.createProcessor();
oXslProcessor.input = oXmlDom;
oXslProcessor.addParameter("message", "My Book List");
这段代码将往XSLProcessor中添加"message"参数。当执行XSL转换时,处理器使用参数的值,"My Book List",并将其放置在相应的位置。XSL中的参数使用<xsl:param/>指令:
<xsl:param name="message" />
请注意,name属性匹配传入addParameter()的名称。该参数接收使用之前介绍的变量语法获取的值"My Book List":
<xsl:value-of select="$message" />
本示例中,通过<xsl:value-of/>指令得到参数值。更新后的XSL样式表如下所示:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="message" />
<xsl:template match="/">
<html>
<head>
<link rel="stylesheet" type="text/css" href="books.css" />
</head>
<body>
<xsl:value-of select="$message" />
<xsl:apply-templates />
</body>
</html>
</xsl:template>
更新后的样式表增加两行新的代码。第一行代码是<xsl:param/>指令,第二行代码则是获取参数值的<xsl:value-of/>指令。参数声明可以在XSL文档的任何位置出现。这段代码在文档顶部进行参数声明,但是并不限制只能在文档顶部出现。
使用XSLProcessor的最后一个特性是它的速度。XSLProcessor编译XSL样式表,所以后续的转换可以使用相同的样式表结果,转换速度更快(与使用transformNodes()相比)。如果要这样做,那么需要使用XSLProcessor对象的reset()方法。该方法清空input和output属性,但没有清空stylesheet属性。这就让处理器为下次基于相同样式表的转换做好了准备。







