XSLT 实现更好的灵活性和方便
Benoit Marchal(bmarchal@pineapplesoft.com)
顾问,Pineapple Software
2001 年 8 月
在这篇详细的技巧说明中,Benoit Marchal 说明了当保存 XML 文件时,SAXTransformerFactory
— 直接在 XSLT 处理器中提供 SAX 事件的类 — 如何带给您更好的灵活性。几段可重用 Java 代码样本演示了该技术,这些代码样本需要使用
TrAX。
我使用的大多数 Java 应用程序都将其数据保存成 XML 格式。我喜欢 XML 的原因之一就是使用 XSLT 后处理文件很容易。例如,我通常以
XML 格式保存原始数据,并使用一两个样式表来生成 HTML、PDF 和 SVG 格式的报表。
我过去常常使用单独的应用程序来后处理文件,但用户逐渐要求使用一个集成的解决方案来模拟他们熟悉的商业生产应用程序中的“导出...”或“另存为...”菜单命令。
在搜寻好的解决方案的过程中,我最终找到了 SAXTransformerFactory。对于本讨论的其余部分,我假设您已经了解
SAX 语法分析、TrAX(XSLT 处理器的标准 Java API)和 XSLT。如果需要了解一些背景知识,请参阅参考资料以获取参照。
SAX 和 XSLT 处理器
您知道,SAX 语法分析要求您编写处理语法分析器事件的 ContentHandler。SAXTransformerFactory
实质上是将 XSLT 处理器转换成 ContentHandler。
您也许会问,为什么要那么麻烦?毕竟,TrAX 还支持 SAXSource 以便与 SAX 语法分析器结合。的确,如果使用成熟的
SAX 语法分析器,SAXTransformerFactory 就没什么用处了。但我发现,在没有语法分析器的情况下,从我的应用程序生成那些事件还是合算的。
请考虑图 1。其中发生了两件事:首先应用程序将数据写入 XML 文件,然后 XSLT 处理器(另一个应用程序)将数据整理成 HTML 格式。
如果将 XSLT 处理器集成到应用程序中,会发生什么?仍必须向它提供 XML 文档。为满足该目的,大多数应用程序都使用临时文件或字符串。我相信,ContentHandler
更具有吸引力。
的确,在第一种情况中,应用程序编写了 XSLT 处理器可以立即分析的 XML 文档(通常通过 SAX 语法分析器)。如图
2 所示,如果应用程序发出 SAX 事件本身,是否会更有效呢?在图 2 中,应用程序并没有写到文件中,而是直接调用处理器的 ContentHandler,有效地模拟了语法分析器。
第二种模式更有效,它使用较少的内存,并省去了创建和删除临时文件的烦恼。
模拟语法分析器
此外,它使模拟语法分析器变得很简单。应用程序很可能已经拥有了写开始标记、结束标记和转义符的功能。它可以将它们替换成 SAX 等价物,分别替换成
startElement()、endElement() 和 characters()。换句话说,代码
writer.write("<ps:key>") 变成
contentHandler.startElement ("http://www.psol.com/2001/08/dw/tip","key","ps:key",attributes)。它也许会更长,但写起来不会很费劲。
asXML() 方法将 Properties 对象写成 XML 格式,但它没有写到文件中;而是使用
ContentHandler。
如果没有名称空间,代码会很简单。经验显示发出 startPrefixMapping() 并将 xmlns
声明当作常规属性传送会更安全。
清单 1. asXML() 模拟 SAX 语法分析器
|
调用 XSLT 处理器
要对 asXML() 的结果应用样式表,请使用清单 2
中的代码。首先,就象常规 TrAX 一样,创建 TransformerFactory。接着,通过调用 getFeature()
确保它与 SAXTransformerFactory 兼容,如果成功,将它强制类型转换成 TransformerFactory。
最后,使用 newTransformerHandler() 来请求 TransformerHandler
对象。该方法使用样式表的 URI 作为参数。TransformerHandler 实现了 ContentHandler,并且可以作为参数传递给
asXML()。
如果熟悉 TrAX,您也许想要知道在哪里调用 transform()。答案是不必这样做。TransformerHandler
在接受 SAX 事件时会应用样式表。
HTML 样式表
TransformerHandler 是常规 XSLT 处理器;它对样式表没有限制,如“清单 3”中的 table.xsl。
清单 3. table.xsl


