数据绑定 提供了一种简单而直接的方法,以在 Java 平台应用程序中使用 XML。有了数据绑定,应用程序可以在很大程度上忽略 XML 文档的实际结构,而 直接使用那些文档的数据内容。虽然这种方法不能适合于所有应用程序,但在一 般情况下,对于那些将 XML 用于数据交换的应用程序是比较理想的。
除了简化编程之外,数据绑定还提供了其它一些好处。由于数据绑定对许多文 档细节进行了抽象,因此对于在内存中处理文档,它通常所需要的内存比文档模 型方法(譬如 DOM 或 JDOM)要少。您还会发现,由于不需要遍历文档结构以获 取数据,因此用数据绑定方法访问程序内的数据要比用文档模型方法快。最后, 在输入时,一些特殊类型的数据(譬如数字和日期)可以被转换成内部表示,而 不是保留为文本形式;这使应用程序可以更有效地使用数据值。
您可能想知道,如果数据绑定有这么多的好处,那么何时使用文档模型方法呢 ?基本上在以下两种主要情形下需要用文档模型方法:
当应用程序确实要关注文档结构的细节时。例如,如果您正在编写一个 XML 文档编辑器,则您会希望采用文档模型,而不是使用数据绑定。
当正在处理的文档不需要遵循固定的结构时。例如,对于实现常规的 XML 文 档数据库,数据绑定不是一种很好的方法。
回到绑定
去年,我写了一篇文章,讲述了如何使用 Castor 框架以进行 Java 对象到 XML 文档的映射数据绑定。我曾经答应要写一篇后续文章,其中将探讨代码生成 方法,包括介绍 JAXB,Java Community Process(JCP)正在开发 JAXB,它是用 Java 语言编写的、用于数据绑定的标准 API。就在较早的那篇文章发布不久, Sun 宣布对 JAXB 的方向做出了重大调整。由于这方面的变化,所以我想,为了 更贴近最终的 JAXB 代码,最好先不写这篇后续文章,现在,我很高兴,终于可 以写这篇文章了!
数据绑定字典
下面是一个微型字典,里面包含了我在本文中所使用的一些术语:
文法 (Grammar) 是用于定义一系列 XML 文档结构的一套规则。其中一类文法是 XML 规范所定义的文档类型定义(Document Type Definition,DTD)格式。另一类日 渐普及的文法是 XML Schema 规范所定义的 W3C XML Schema(Schema)格式。文 法定义了哪些元素和属性可以出现在文档中,以及在文档中元素是如何嵌套的( 通常包括嵌套元素的次序和数目)。一些类型的文法(譬如 Schema)还可以更进 一步,使字符数据内容与特定数据类型甚至正则表达式相匹配。在本文中,我会 常使用术语 描述, 将它作为引用一系列文档的文法的非正式方法。
编组 (Marshalling)是在内存中为对象生成 XML 表示的过程。与 Java 对象序列化 一样,这种表示需要包含所有依赖的对象:我们的主对象引用的对象、这些对象 引用的对象等等。
数据分解(Unmarshalling) 是与编组相反的过程,在内存 中根据 XML 表示构建一个对象(而且可能是链接对象的图)。
在本文中,我将讨论根据 XML 文档文法生成 Java 语言代码的五种 XML 数据 绑定框架:JAXB、Castor、JBind、Quick 和 Zeus。它们都可以免费获取,除了 JAXB 之外,其它四种框架都可以在开放源码和专利项目中使用。当前 JAXB 参考 实现 beta 测试版的许可证只允许用于评估,但当它作为产品发行时,这种情形 很可能会改变。JAXB、Castor 和 JBind 都提供了根据 XML 文档的 Schema 描述 生成代码,而 Quick 和 Zeus 根据 DTD 描述生成代码。Castor 和 Quick 还支 持将现有类映射到 XML,以此作为另一种生成代码的方法。
这些框架各有优缺点,所以我会试图逐步指出每种框架所具有的最佳(和最差 )特性。在第 2 部分,我将进一步向您显示这些框架如何对一些样本文档进行处 理,另外,还将探讨,对于许多类型的应用程序,现有的数据绑定框架怎么会缺 乏一些重要的特性。
相对于我在以前文章中所描述的映射绑定方法,根据 Schema 或 DTD 文法生 成 Java 语言代码具有一些突出的优点。使用生成的代码,您可以确定数据对象 被正确地链接到 XML 文档,不象映射绑定方法,需要直接指定链接,并确保正确 地涵盖了所有的结构变体。在使用 Schema 时,甚至可以利用文法所提供的类型 信息,用合适的数据类型来生成代码。
代码生成方法也有一些不足之处。这种方法造成应用程序数据结构与 XML 文 档结构之间紧密耦合。另外,它还可能限定您使用简单的数据类(没有关联行为 的被动数据容器),而不是真正的对象类,在编组和数据分解过程中,还可能限 制应用数据的定制转换的灵活性。在本文后面,我会权衡代码生成和映射绑定这 两种方法。
数据和代码
对于将在第 2 部分中讨论的性能测试,我用每一种数据绑定框架来生成代码 。用于性能测试的文档包含模拟航班时刻表的信息。下面是一个样本文档,您可 以感受一下其中的结构:
清单 1. 样本文档
<?xml version="1.0"?>
<timetable>
<carrier ident="AR">
<rating>9</rating>
<URL>http://www.arcticairlines.com</URL>
<name>Arctic Airlines</name>
</carrier>
<carrier ident="CA">
<rating>7</rating>
<URL>http://www.combinedlines.com</URL>
<name>Combined Airlines</name>
</carrier>
<airport ident="SEA">
<location>Seattle, WA</location>
<name>Seattle-Tacoma International Airport</name>
</airport>
<airport ident="LAX">
<location>Los Angeles, CA</location>
<name>Los Angeles International Airport</name>
</airport>
<route from="SEA" to="LAX">
<flight carrier="AR">
<number>426</number>
<depart>6:23a</depart>
<arrive>8:42a</arrive>
</flight>
<flight carrier="CA">
<number>833</number>
<depart>8:10a</depart>
<arrive>10:52a</arrive>
</flight>
<flight carrier="AR">
<number>433</number>
<depart>9:00a</depart>
<arrive>11:36a</arrive>
</flight>
</route>
<route from="LAX" to="SEA">
<flight carrier="CA">
<number>311</number>
<depart>7:45a</depart>
<arrive>10:20a</arrive>
</flight>
<flight carrier="AR">
<number>593</number>
<depart>9:27a</depart>
<arrive>12:04p</arrive>
</flight>
<flight carrier="AR">
<number>102</number>
<depart>12:30p</depart>
<arrive>3:07p</arrive>
</flight>
</route>
</timetable>