如果使用 XSLT 转换把数据呈现为 HTML 并决定在客户端执行 XSLT 转换,还需要做进一步的选择。XML 数据文档可以使用链接样式表。这种情况下,浏览器将尝试加载该样式表、执行转换并呈现结果。但 XML 文档是数据。不应该规定它的可视化呈现。实际上,它有可能在应用程序的不同地方呈现为不同的形式。比如,一个页面可能像 清单 1 那样显示整个 CD 目录,而下一个页面可能通过层层选择只显示 Bonnie Tyler 的 CD。
可以将视图和数据分开,通过客户机 JavaScript 执行转换。JavaScript 决定执行什么样的转换或者通过提供转换参数来控制它。
这里判断浏览器的类型非常重要。Internet Explorer 6.0 及以下版本通过私有的 ActiveX 控件执行 XSLT,而 Mozilla 和 Opera 使用内建的 XSLTProcessor
对象。Internet Explorer 7.0 将支持 XSLTProcessor
,但是您不能指望整个公共 Web 社区都装上了新的浏览器。
另一方面,如果企业 WAN 指定了某种浏览器,就可以把内部应用程序设计成与这种浏览器捆绑在一起。当然,如果企业要发布新的指定,您可能会后悔引入了这种依赖性。这些是在设计应用程序时必须要考虑和权衡的。
我们用脚本来实现一个 XSLT 转换。可以从 W3Schools 获得 清单 1 所示的 cdcatalog.xml(详情参阅 参考资料)。
清单 1. cdcatalog.xml
<?xml version="1.0" encoding="utf-8"?> <catalog> >cd> <title>Empire Burlesque</title> <artist>Bob Dylan</artist> <country>USA</country> <company>Columbia</company> <price>10.90</price> <year>1985</year> </cd> <cd> <ttitle>Hide your heart</title> <artist>Bonnie Tyler</artist> <country>UK</country> <company>CBS Records</company> <price>9.90</price> <year>1988</year> </cd> <cd> . . . <catalog> |
然后再从 W3Schools 下载 cdcatalog.xsl,如 清单 2 所示。该样式表生成一个 HTML 文件表格,按照在文档中存在的顺序(如果需要也可以在转换中增加排序)列出了收藏的 CD。
清单 2. cdcatalog.xsl
<?xml version="1.0" encoding="ISO-8859-1"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <html> <body> <h2>My CD Collection</h2> <table border="1"> <tr bgcolor="#9acd32"> <th align="left">Title</th> <th align="left">Artist</th> </tr> <xsl:for-each select="catalog/cd"> <tr> <td><xsl:value-of select="title" /></td> <td><xsl:value-of select="artist" /></td> </tr> </xsl:for-each> </table> </body> </html> </xsl:template> </xsl:stylesheet> |
然后建立 ajax.js 脚本,如 清单 3 所示,保存在和 XML 文件与 XSL 文件相同的工作目录中。该脚本是独立于浏览器的。Mozilla 或 Opera 浏览器使用的 createRequest
函数返回一个 XMLHttpRequest
对象,通过 URL 请求一个文件。请注意,对于 Internet Explorer 浏览器,它返回一个 Microsoft ActiveX® 对象。
清单 3. ajax.js
function createRequest() { var request = null; try { request = new XMLHttpRequest(); } catch (tryIE) { try { request = new ActiveXObject("Msxml2.XMLHTTP"); } catch (otherIE) { try { request = new ActiveXObject("Microsoft.XMLHTTP"); } catch (failed) { request = null; } } } if (request == null) { alert("Could not create request object"); } else { return request; } } |
现在创建 清单 4 所示的 HTML 文件,其中的 JavaScript 代码创建了两个异步请求对象。它使用一个请求对象加载 XML 文件,另一个请求对象加载 XSL 文件。这些对象不能重用,因此需要两个。
脚本使用 XSLTProcessor
对象应用转换,然后创建 DOM 节点。它将该 DOM 节点插入 HTML div
节点,完成 CD 目录的呈现。要在文档加载过程中调用 render
函数,因此调用必须出现在文档快结束的时候,在 div
标签之后,以便能够访问这个标记。
清单 4. catalog.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html> <body> <script type="text/javascript" src="ajax.js"> </script> <script type="text/javascript"> function render(insertionID){ var request1 = createRequest(); var request2 = createRequest(); // load the xslt file request1.open("GET", "cdcatalog.xsl", false); request1.send(null); var xslStylesheet = request1.responseXML; var xsltProcessor = new XSLTProcessor(); xsltProcessor.importStylesheet(xslStylesheet); // load the xml file request3.open("GET", "cdcatalog.xml", false); request2.send(null); var xmlDoc = request2.responseXML; var fragment = xsltProcessor.transformToFragment(xmlDoc, document); document.getElementById(insertionID).innerHTML = ""; document.getElementById(insertionID).appendChild(fragment); } </script> <div id="example"/> </body> <script type="text/javascript"> render("example") </script> </html> |
图 1 显示了在 Firefox 浏览器中的执行结果。在 Opera 上应该也能正常运行。但是在 Internet Explorer 6.0 或更低版本中不能工作,因为缺少 XSLTProcessor
对象。
图 1. W3Schools 脚本例子在 Firefox 中的运行结果
清单 5 显示的 catalogIE.html 按照 Internet Explorer 的方式执行同样的转换。该页面只能在 Internet Explorer 中打开,而不能用于 Firefox 或 Opera。如何将两个 JavaScript 控制的转换结合起来留给读者作为练习。如果使用 JavaScript 执行客户端转换,应小心地处理和测试浏览器的依赖问题。
清单 5. catalogIE.html
<html> <body> <script type="text/javascript"> // Load XML into Internet Explorer 6.0 var xml = new ActiveXObject("Microsoft.XMLDOM") xml.async = false xml.load("cdcatalog.xml") // Load XSL into Internet Explorer 6.0 var xsl = new ActiveXObject("Microsoft.XMLDOM") xsl.async = false xsl.load("cdcatalog.xsl") // Transform within Internet Explorer 6.0 document.write(xml.transformNode(xsl)) </script> </body> </html> |