XML 在现在 Java 应用的开发中,很多地方都能看到它的身影,比如最常见的是我们定义参数配置文件用的就是 XML 文件格式,避免程序的硬编码。当然,XML 的应用不仅限于此,在其他技术领域 XML 也占有举足轻重的位置。如何在 Java 中处理 XML 文件?目前最基础最底层的 API 是 DOM, SAX, JDOM, dom4j。这些 API 为 Java 处理 XML 提供了解决方案,但是不足的是他们使用方法复杂,在处理 XML 的时候很容易发生错误。记得在两年前使用 Cocoon 1.8 的时候,因为遗留系统采用 DOM 定义 XML 数据文件格式,大量的子元素、父元素、同级元素、属性让人好半天都没有理出头绪来。
这次我们介绍的 JiBX 是处理 XML 的高级 API,同类的项目还有 JAXB, Castor, Zeus。使用这类高级 API,在处理 XML 的使用,你的 Java 应用中将不再会有元素和属性,取而代之的是对象和值域。优点显而易见,处理 XML 的难度大大降低,而且更加符合面向对象的编程思想。
一 JiBX 简介
JiBX 是一个绑定 XML 数据到 Java 对象的框架。JiBX 用一个绑定定义文挡(binding definition document)来定义 XML 数据与 Java 对象转换的规则,这个文挡就是联系 XML 数据与 Java 对象之间的桥梁。
这里有必要先介绍两个数据绑定术语 marshal 和 unmarshal,marshal 是由 Java 对象生成 XML 文挡,unmarshal 是根据 XML 文挡建立 Java 对象。
使用 JiBX 的过程分成两个过程,一个是 binding compiler,另一个是 binding runtime。binding compiler 是一个前期准备过程,包括定义绑定定义文挡,定义与 XML 绑定在一起的 Java 对象,然后编译。在这个过程,JiBX 比其他项目在操作上要简单,不用定义 DTD 和 Schema,缺点是需要自己定义 Java 程序。binding runtime 是使用 binding compiler 编译好的 Java class 处理 XML 数据。
JiBX 也用到了第三方的工具 XPP3 Pull Parser 和 BCEL,在 JiBX 发布的文件中也包含了这两个工具相关的文件。
二 简单范例
按照惯例,还是从最简单的例子说起。
首先从 JiBX 网站下载 JiBX,当前最新版本是 beta 3。解开下载的 zip 文件,里面有一个 lib 目录,包含了 bcel.jar, jibx-bind.jar, jibx-extras.jar, jibx-run.jar, xpp3.jar 五个 jar 文件。bcel.jar, jibx-bind.jar 只有在 binding compiler 的时候才用得到。jibx-extras.jar 是一个可选的工具包,里面有一些测试和验证的工具类。
1.定义一个我们将要处理 XML 文件,文件名为 data.xml,内容如下:
<person>
<cust-num>123456789</cust-num>
<first-name>John</first-name>
<last-name>Smith</last-name>
</person>
<street>12345 Happy Lane</street>
<city>Plunk</city>
<state>WA</state>
<zip>98059</zip>
<phone>888.555.1234</phone>
</customer>
这个 XML 文件非常简单,共有十个元素,没有属性。根元素 customer 有 person, street, city, state, zip, phone 六个子元素。其中元素 person 有 cust-num, first-name, last-name 三个子元素。
2.接着定义两个 Java 类 Customer 和 Person,也采用最简单的方式,用对象的域值对应元素,内容如下:
public Person person;
public String street;
public String city;
public String state;
public Integer zip;
public String phone;
}
public int customerNumber;
public String firstName;
public String lastName;
}
这个两个类没有任何方法,够简单吧!或许你已经看出来了,Customer 类的七个 field 对应的是 XML 文件中 customer 元素的七个子元素。Person 类的三个 field 对应的是 person 元素的三个子元素。在 Person 类的 field 的名称并不是和 person 元素的子元素名称完全相等,这是遵守 Java 编程规范 field 命名的需要,虽然不相等,但这不重要,可以在绑定定义文挡中把它们一一对应起来。
3.绑定定义文挡
绑定定义文挡是依据绑定定义规范将 XML 数据和 Java 对象绑定的 XML 文挡。文件名为 binding.xml,内容如下:
<mapping name="customer" class="Customer">
<structure name="person" field="person">
<value name="cust-num" field="customerNumber"/>
<value name="first-name" field="firstName"/>
<value style="text" field="lastName"/>
</structure>
<value name="street" field="street"/>
<value name="city" field="city"/>
<value name="state" field="state"/>
<value name="zip" field="zip"/>
<value name="phone" field="phone"/>
</mapping>
</binding>
binding.xml 文件中的 name 和 field 属性分别将 XML 中的元素和 Java 对象中的 field 一一对应并绑定起来。
mapping 元素的 name 和 class 属性将 customer 根元素和 Customer 类绑定在一起。
上面两行定义了 person 是 Customer 的 field,同时也把 person 元素和 person 类绑定在一起。
4.现在来看看他们之间的关系吧,如下图
图片来自 Jibx 官方网站
对于最终用户来说,他们只知道 XML 数据文挡和 Java 类,而绑定定义文挡是透明的。
5.执行 Binding Compiler 过程
以下命令是在 Linux 下执行,如果是 Windows 平台请转换成相应的命令
#javac -classpath . Customer.java
#java -jar lib/jibx-bind.jar binding.xml
执行完后,在当前目录多了四个 class 文件,分别是 Person.class, Customer.class, JiBX_bindingCustomer_access.class, JiBX_bindingFactory.class。
6.执行 binding runtime 过程
首先定制一个 XML 数据文件 data.xml, 内容如下:
<person>
<cust-num>123456789</cust-num>
<first-name>John</first-name>
<last-name>Smith</last-name>
</person>
<street>12345 Happy Lane</street>
<city>Plunk</city>
<state>WA</state>
<zip>98059</zip>
<phone>888.555.1234</phone>
</customer>
接着写一个简单的读取 data.xml 测试程序 Test.java,内容如下:
import java.io.FileNotFoundException;
import org.jibx.runtime.JiBXException;
import org.jibx.runtime.IBindingFactory;
import org.jibx.runtime.BindingDirectory;
import org.jibx.runtime.IUnmarshallingContext;
class Test {
public static void main(String[] args) {
try{
IBindingFactory bfact = BindingDirectory.getFactory(Customer.class);
IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
Customer customer = (Customer)uctx.unmarshalDocument(new FileInputStream("data.xml"), null);
Person person = customer.person;
System.out.println("cust-num:" + person.customerNumber);
System.out.println("first-name:" + person.firstName);
System.out.println("last-name:" + person.lastName);
System.out.println("street:" + customer.street);
}catch(FileNotFoundException e){
System.out.println(e.toString());
}catch(JiBXException e){
System.out.println(e.toString());
}
}
}
编译并运行这个测试程序
#java -cp .:lib/jibx-run.jar:lib/xpp3.jar Test
程序运行的结果是
first-name:John
last-name:Smith
street:12345 Happy Lane
注:上面的compile好象有点问题,我改进了一下 , 如下:
run.bat:
cls
SET CLASSLIB=lib/bcel.jar;lib/jibx-bind.jar;lib/jibx-extras.jar;lib/jibx-run.jar;lib/xpp3.jar
SET CLASSPATH=.%LOCALCLASSPATH%;%CLASSLIB%;
SET JAVA_BIN=C:/j2sdk1.4.1_02/bin
%JAVA_BIN%/JAVAC Person.java Customer.java
%JAVA_BIN%/JAVA -classpath lib/jibx-run.jar -jar lib/jibx-bind.jar binding.xml
%JAVA_BIN%/JAVAC -classpath %CLASSPATH% -sourcepath Customer JibxTestMain.java
%JAVA_BIN%/JAVA -cp %CLASSPATH% JibxTestMain
三 总结
总的来说,JiBX 就这么简单,不过 JiBX 还有一稍微复杂一点的应用,本文没有介绍,感兴趣的朋友可以继续研究下去。如果你有什么问题可以直接到我们的论坛 http://www.sentom.net/forum 提出,也非常欢迎把你的经验给大家分享。