Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1530232
  • 博文数量: 3500
  • 博客积分: 6000
  • 博客等级: 准将
  • 技术积分: 43870
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-03 20:31
文章分类

全部博文(3500)

文章存档

2008年(3500)

我的朋友

分类:

2008-05-04 19:59:17

一起学习
利用 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 语法分析要求您编写处理语法分析器事件的 ContentHandlerSAXTransformerFactory 实质上是将 XSLT 处理器转换成 ContentHandler

您也许会问,为什么要那么麻烦?毕竟,TrAX 还支持 SAXSource 以便与 SAX 语法分析器结合。的确,如果使用成熟的 SAX 语法分析器,SAXTransformerFactory 就没什么用处了。但我发现,在没有语法分析器的情况下,从我的应用程序生成那些事件还是合算的。

请考虑图 1。其中发生了两件事:首先应用程序将数据写入 XML 文件,然后 XSLT 处理器(另一个应用程序)将数据整理成 HTML 格式。

图 1. 典型的 XML 和 XSLT 应用程序
后处理 XML 文件

如果将 XSLT 处理器集成到应用程序中,会发生什么?仍必须向它提供 XML 文档。为满足该目的,大多数应用程序都使用临时文件或字符串。我相信,ContentHandler 更具有吸引力。

的确,在第一种情况中,应用程序编写了 XSLT 处理器可以立即分析的 XML 文档(通常通过 SAX 语法分析器)。如图 2 所示,如果应用程序发出 SAX 事件本身,是否会更有效呢?在图 2 中,应用程序并没有写到文件中,而是直接调用处理器的 ContentHandler,有效地模拟了语法分析器。

第二种模式更有效,它使用较少的内存,并省去了创建和删除临时文件的烦恼。

图 2. 应用程序模拟语法分析器
应用程序模拟语法分析器

模拟语法分析器
此外,它使模拟语法分析器变得很简单。应用程序很可能已经拥有了写开始标记、结束标记和转义符的功能。它可以将它们替换成 SAX 等价物,分别替换成 startElement()endElement()characters()。换句话说,代码 writer.write("") 变成
contentHandler.startElement ("","key","ps:key",attributes)。它也许会更长,但写起来不会很费劲。

asXML() 方法将 Properties 对象写成 XML 格式,但它没有写到文件中;而是使用 ContentHandler

如果没有名称空间,代码会很简单。经验显示发出 startPrefixMapping() 并将 xmlns 声明当作常规属性传送会更安全。

清单 1. asXML() 模拟 SAX 语法分析器


protected static void asXML(Properties properties,ContentHandler contentHandler)

   throws SAXException

{

   AttributesImpl attributes = new AttributesImpl();

   contentHandler.startDocument();

   contentHandler.startPrefixMapping("ps",

	   "");

   attributes.addAttribute("","ps","xmlns:ps","CDATA",

	   "");

   contentHandler.startElement("",

	   "properties","ps:properties",attributes);

   attributes.clear();

   Enumeration enumeration = properties.propertyNames();

   while(enumeration.hasMoreElements())

   {

      String name = (String)enumeration.nextElement(),

             value = properties.getProperty(name);

      contentHandler.startElement("",

		   "property","ps:property",new AttributesImpl());

      contentHandler.startElement("",

		   "key","ps:key",attributes);

      contentHandler.characters(name.toCharArray(),0,name.length());

      contentHandler.endElement("",

		   "key","ps:key");

      contentHandler.startElement("",

		   "value","ps:value",attributes);

      contentHandler.characters(value.toCharArray(),0,value.length());

      contentHandler.endElement("",

		   "value","ps:value");

      contentHandler.endElement("",

		   "property","ps:property");

   }

   contentHandler.endElement("",

	   "properties","ps:properties");

   contentHandler.endPrefixMapping("ps");

   contentHandler.endDocument();

}

调用 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
















   

      Properties

   

   

      

            
KeyValue

整理成原始 XML
如果不想要 HTML,而更喜欢原始 XML 文档,会发生什么?最简单的解决方案是提供一个额外的样式表,该样式表不修改输入,如“清单 4”中的 identity.xsl。

清单 4. identity.xsl














   

      

   





提高性能的序列化程序
如果您关心性能,那么会首选使用序列化程序。序列化程序是 ContentHandler,它将其输入写入 XML 文档。如果您的 XSLT 处理器是 Xalan,请使用 org.apache.xalan.serialize.Serializer。由于它是 ContentHandler,它会直接使用 asXML(),如清单 5 所示。

SAXTransformerFactory 的其它应用程序
如果分几个阶段来处理 XML 文档,SAXTransformerFactory 也会有用。例如,我最近在所谓的“管道”中实现了它,该“管道”通过 XSLT 样式表和定制过滤器的组合来转换输入文档。

参考资料

  • Xalan 是支持 SAXTransformerFactory 的开放源码 XSLT 处理器
  • SAX,功能强大的 API,这是从作者著作 XML by Example 第二版中摘录的一章,Que Publishing 将在 2001 年 9 月发行该书,该书详细地讨论了 SAX。
  • Brett McLaughlin 撰写的 Sun's Java API for XML Parsing, Version 1.1,此文介绍了结合了 SAX、TrAX 和 DOM 的 JAXP 1.1。请转向 Sun 公司的官方网页 Java Technology and XML。
  • David Mertz 撰写的使用 XSLT 转换 DocBook 文档是学习 XSLT 的一个好的起点。
  • Michael Kay 撰写的 Saxon: 剖析 XSLT 处理器是关于 XSLT 处理器最有趣的讨论。
  • IBM FAQs 回答了关于 XML 和 IBM 产品的常见问题。
  • The XML certification guidelines 提供了掌握在 IBM Certified Developer Program 中进行 XML 开发需要的详细技术。
下载本文示例代码


利用XSLT 实现更好的灵活性和方便利用XSLT 实现更好的灵活性和方便利用XSLT 实现更好的灵活性和方便利用XSLT 实现更好的灵活性和方便利用XSLT 实现更好的灵活性和方便利用XSLT 实现更好的灵活性和方便利用XSLT 实现更好的灵活性和方便利用XSLT 实现更好的灵活性和方便利用XSLT 实现更好的灵活性和方便利用XSLT 实现更好的灵活性和方便利用XSLT 实现更好的灵活性和方便利用XSLT 实现更好的灵活性和方便
阅读(121) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~