XML 和 Java 技术: XML 持久性的三种方式

序列化、TrAX 和数据绑定:哪种方法更适合您?

级别: 初级

Brett D. McLaughlin, Sr. ([email protected]), 作家兼编辑, O'Reilly Media, Inc.

2007 年 10 月 22 日

使用 XML 可以实现各种有趣的功能,但是如果无法将其持久化保存到文件中,那么一切都将是徒劳而已。Brett McLaughlin 将讨论实现 XML 持久化存储的各种不同的技巧,并分别比较其优点和缺点。
<!--START RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --><!--END RESERVED FOR FUTURE USE INCLUDE FILES-->

必须将 XML 存储在某个地方

XML 是一种伟大的数据格式 — 显而易见,整个 IBM developerWorks 专区都在专注于研究这个主题。2007 年,关于 XML 的讨论多半是 Web 服务,或者 XML 和 Java™ 对象之间的转换,或者读取 XML 配置文件,或者甚至是使用 XML 格式的数据库代替关系或面向对象的数据库。

目前,我们还没有听到有人在谈论如何将所使用的内存表示 — DOM、JDOM 等等 — 中的 XML 保存到静态文件中去,并在其中填满尖括号和引号。坦白的说,获取 XML 并将其写入文件算不上激动人心 — 不过这却是有必要的。试问,编程领域若永远都不能将 XML 持久化存储到文件中会是怎样一番情境?您可以在内存中创建 XML 文档,并且甚至可以将其发送给应用程序中的其他组件(或者其他应用程序的组件);但是却无法存储这些 XML。您可以使用 XML 存储配置数据,同时编写各种工具来读取该数据,但是实际上却无法存储配置文件本身。您甚至还可以读取 SOAP 信封的内容 — 但是却无法将这些内容存储在磁盘上,以供应用程序离线时使用。

显然,将 XML 写入文件非常重要。事实上,如果只是想将数据停留在内存中并且不需要担心数据的存储方式,您可以想象得到不需要存储 XML 的编程世界是什么样子,毫无疑问这在如今的编程领域中是不可能的。

因此,问题十分简单:如何将 XML 持久化存储到文件中去?我假定本文的读者需要自己处理这一任务。换句话说,如果您在编程中从未涉及到持久化存储 XML,那么本文将使您受益匪浅。(但是,了解如何执行这些任务会更利于对文章的理解)对于那些确实关注持久性存储的人,我总结了三种相当常用的主流方法:

  1. 使用 DOM 和 JDOM 之类的 API 将 XML 数据结构直接写入文件
  2. 使用 Transformation API for XML (TrAX) 和标识转换(identity transformation)持久化存储您的 XML
  3. 使用 JAXB 之类的较高级别的 API 处理持久化存储

直接使用 API

如果使用一个或多个 API 读取 XML,那么很明显的一个方法就是使用与之相同的 API 将 XML 写入文件。比如说,如果您使用 JDOM API 和一个 JDOM Document 对象操作 XML,那么可以编写以下代码:

XMLOutputter outputter = new XMLOutputter();
outputter.setFormat(Format.getPrettyFormat());
outputter.output(myDocument, new FileWriter("outputFile.xml"));

与此类似,在 DOM Level 3 中可以使用新的 Load 和 Save API:

DOMWriter writer = new org.apache.xml.serialize.XMLSerializer();
writer.setNewLine("\r\n");
writer.setEncoding("UTF-8");
writer.writeNode(new FileOutputStream(new File("outputFile.xml")), myDocument);

注意,使用新 DOM API 的方法多种多样,其中有一些具有较低的供应商独立性。上面的示例代码中含有一个特定于 Xerces 的类,但是其他方法不会像它一样与某个特定的供应商类紧密绑定在一起。从学习的角度来说,那些方法都不够直观,因此我保留了特定于供应商的代码。

优点

这种方法的优势是可以相当直接地与您的 API 进行交互,从而实现良好和全面的控制。您可以设置新行,您可以处理首行缩进,您可以控制输出文件的各个方面。此外,还可以尽可能拉近您与文件之间的距离;即没有包装器 API 也没有间接层,您可以直接编写 XML。如果您对 JDOM 和 DOM 比较熟悉,那么它们将是输出 XML 的不二选择。

缺点

任何方法有优点就必然有缺点。虽然您可以全面地控制输出的各种细节,但是如果输出配置不当则会导致诸多混乱的问题。换行错误,编写错误和 I/O 错误都是这种方法产生的一些常用问题。除此之外,您还工作于一个非常低的层次,并没有大量的辅助工具(JDOM 在 Format.getPrettyFormat()Format.getCompactFormat() 方法中提供了一些:而 DOM 几乎是一毛不拔)。这意味着您必须要理解编码、输出格式、缩进格式,以及对输出有影响的任何内容。

转换格式

另一个流行的选择是使用 TrAX 和标识转换。TrAX 是 Transformation API for XML 的缩写,它现在是 JAXP 的一部分,而 Java 平台的每一个发行版中都含有 JAXP(除了 Micro Edition)。TrAX 允许您使用 XSL 样式表对 XML 进行转换。由于 XML 经常需要结合 SAX 和 DOM 一起使用,因此 TrAX 可以接收 SAX 事件和 DOM Document 作为输入,并能够轻易地产生输出文件。此外,TrAX 还可以轻松地对这些格式进行相互转换。比如说,您可以使用以 DOM 表示的 XML 文档作为输入,并对它进行转换,然后再将输出发送到文件中。或者您也可以读取文件中的内容,并对它进行转换操作,然后再将结果文档存储到 DOM Document 中。

这种方法的另外一个作用是,您可以使用一个不含任何文档操作的样式表,并使用某种格式作为输入,然后将这种格式输出为任意其他的格式。使用不具转换功能的样式表 — 实际上指不执行任何操作但回转所接收的输入内容的样式表 — 称作 标识转换(identity transformation)。因此您可以从文件中获得文档,然后应用标识转换,最终在 DOM Document 中生成相同的 XML。如果您采用相反的方式 — 从 DOM 到文件 — 那么实际上可以实现持久化存储 XML。这种方法类似于以下过程:

Source domSource = new DOMSource(myDOMDocument);
Result fileResult = new StreamResult(new File("outputFile.xml"));
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
transformer.transform(domSource, fileResult);

此处,DOM 文档中的 XML 最终转换为了一个 outputFile.xml 文件。

TrAX 的优点

TrAX 最大的优点就是易于使用。拥有 Java 平台访问权的任何人都可以使用它,并且不需要对 SAX 或 DOM 有深入的了解。因此,这对于只有基本 XML 编程技能的开发人员来说是一个极具吸引力的选择。此外,不熟悉 SAX 或 DOM 的初级程序员也可以使用 TrAX — 只需要了解 10 到 20 行函数代码 — 快速将 XML 持久化存储到文件中,或者甚至是 DOM Documents 和 SAX 事件中。

TrAX 的缺点

使用 TrAX 的最大缺点是:虽然可以很容易执行标识转换,但是处理输出细节却需要很高的技巧。换行、编码、空格和缩进 — 所有这些都是 TrAX 提供的配置选项,但是它并不像使用 DOM 或 JDOM 直接配置那样简单。在大多数情况下,TrAX 为普通任务所提供的易用性常常伴随着较低的灵活性,至少不能开箱即用。

注意:在输出方面,使用 TrAX 和标记转换几乎可以实现 JDOM 或 DOM 可以完成的所有任务;只是不够简单或直观而已。您只需要了解一些 XSLT 和 TrAX API 的知识,这两者与所执行的实际输出任务并没有密切的联系。

使用数据绑定实现持久化存储

将 XML 转换为静态格式的另一种方法 — 特别是您希望这种格式是位于磁盘上的文件 — 是使用 JAXB 之类的数据绑定 API。虽然通常人们不会考虑使用数据绑定来实现持久化存储,但是它可以有效地实现:读取内存中表示的 XML 文档并将其写入文件。

我没有太多时间详细介绍数据绑定的概念(您可以在 developerWorks 网站上阅读一些这方面的文章);下面这段简短的代码使用了 JAXB 方式的数据绑定实现持久性存储:

FileOutputStream stream = new FileOutputStream("outputFile.xml");
Marshaller marshaller = myJaxbContext.createMarshaller();
marshaller.marshal(myJavaObject, stream);

您可以设置一些选项,比如说输出文件的编写,所有设置都在 Marshaller 对象中。事实上,JAXB 在设置输出属性方面的灵活性与前面两种方法是不相上下的。

JAXB 的优点

JAXB 的最大优点就是:它具有极大的易用性,特别是对于一些简单的任务。同时,虽然人们仍然认为 SAX 和 DOM 是主流方法(至少在普通 Java 编程领域是如此),但是 JAXB 对于使用 Java 语言的任何人来说都是家常便饭。这意味着我们可以找到更多 JAXB 方面的文章和教程(2007 发布的一篇调查文章将证实这一点)。此外,对 JAXB 的支持也要优于 DOM 和 SAX。SAX 和 DOM 是 Java 平台标准版本的一部分,而 JAXB 在很大程度上是由 Sun Microsystems, Inc. 发明的。因此,JAXB 的支持稍高一筹也不足为奇了。

此外,使用 JAXB 基本不需要掌握任何 XML 知识。您可以操作普通 Java 对象 — 不是特定于 XML 的对象,如 DOM 的 NodeText 接口 — 并将这些对象直接表示为 XML。这意味着较低的入门门槛,并且任何人都希望可以在很短的时间内掌握它,尤其是当老板在办公室对着您颐指气使的时候。

JAXB 的缺点

有其利必有其弊。JAXB 的不足之外在于我们不需要过多了解 XML 便可以使用它。这看上去似乎是我刚刚提到的优点,但是它同时也潜藏着缺点。对 XML 的了解越少,要合理使用 JAXB 就愈加显得困难。您可以轻松地生成一个 XML 文件,但是却会发现这个文件的格式并不可用,或者它只含有一部分需要持久化存储的对象,或者其中的对象与您所编制的对象并不相同。

所有这些常常会导致开发人员将 JAXB 放在一旁,或者大量学习 XML、SAX 和 DOM 方面的知识。这样一来,许多开发人员都会继续使用 SAX 和 DOM 实现持久性存储,而使用 JAXB 只是为实现其最简单的功能:在 XML 和 Java 对象之间相互转换。

另一种选择……

我特意将最后一种选择留给大家思考:将 XML 作为一系列比特、节点和字符串直接写入 FileOutputStreamFileWriter。毫无疑问,这种方法可以将 XML 写入文件,并且这种方法的采用也相当多;但是在本例中,持久化存储已有 XML 数据并没有从非 XML 格式的数据中创建 XML 那么频繁。您可以认出这种代码,它们通常类似于以下形式:

String xmlString = setupXMLBuffer(
  new StringBuffer("<firstName>")
       .append(customer.firstName)
       .append("</firstName>")
       .append("<lastName>")
       .append(customer.lastName)
       .append("</lastName>")
  // etc...
       .toString()
);
bufferedWriter.write(xmlString);
// other file I/O code

这段代码并没有任何错误;我们只是将数据持久化存储于 XML 中,所有操作都在一步之内完成。因此,关于如何持久化存储数据,以及哪种方式是最佳的,这些问题都无关紧要。写入数据并将其存入 XML 的操作是无法分开的,因此再多的讨论也无济于事。

结束语

我们应该如何处理 XML 持久性存储呢?并没有完全正确的答案。也就是说,Java 和 XML 开发人员都需要经过仔细讨论才能做出选择。您趋向于使用一致的方法解决通用问题吗?有没有一种持久性存储方法可以在磁盘上生成易于读取、使用并能发送给其他应用程序的 XML 文档呢?

对于大多数技巧,我的观点是人们应该重点关注这些技巧是否能够真正奏效。如果您发现某个技巧更适用于其他人,那么您应该能够提高自己的编程技巧 — 至少,这是基本思想!因此,请花几分钟逛逛 developerWorks 网站的 Java 和 XML 论坛(请参阅 参考资料 获得访问链接),并让我们知道您所使用的持久性存储方法。如果需要基于一些特定的功能,也请告诉我们。我希望能在论坛中见到您的身影。

参考资料

学习

  • 您可以参阅本文在 developerWorks 全球网站上的 英文原文

  • Sun's online Java 和 XML 总部:说到 JAXP,您将发现没有比 Sun 公司的在线页面更佳的地方了。

  • 核 心 API 文档 用于 Java 5.0 技术:获取有关 JAXP JavaDoc 的信息,现在已集成在这一规范中。

  • SAX Web 站点:找到更多有关 JAXP 的 API。开始了解用于 Java 环境的 SAX 2。

  • W3C Web 站点:有关 SAX 支持的 XML 的另一看法,请了解 DOM。

  • Apache Xerces 解析器:了解 Sun 在他们的 JDK 5.0 实现中所使用的解析器。

  • XML 入门(Doug Tidwell,developerWorks,2002 年 11 月):想了解 XML 的基础知识吗?请阅读这篇教程和一些 其他培训服务,其中介绍的都是最基本的内容。

  • IBM XML 认证:看看如何才能成为一名 IBM 认证的 XML 及相关技术的开发人员。


讨论

关于作者

Photo of Brett McLaughlin

Brett McLaughlin 从 Logo 时代就开始使用计算机。(还记得那个小三角吗?)近年来他已经成为 Java 技术和 XML 社区最知名的作家和程序员之一。他曾经在 Nextel Communications 实现过复杂的企业系统,在 Lutris Technologies 编写应用程序服务器,最近在 O'Reilly Media, Inc. 继续撰写和编辑这方面的图书。在他的新书 Head Rush Ajax 中,Brett 与畅销书作家 Eric 及 Beth Freeman 为 Ajax 带来了获奖的创新方法 Head First。他的上一本书 Java 1.5 Tiger: A Developer's Notebook 是第一本可获得的关于最新版本 Java 技术的书籍,而他的经典著作 Java and XML 仍然是在 Java 语言中使用 XML 技术的权威图书。

你可能感兴趣的:(java,编程,应用服务器,xml,企业应用)