Chinaunix首页 | 论坛 | 博客
  • 博客访问: 702793
  • 博文数量: 147
  • 博客积分: 6010
  • 博客等级: 准将
  • 技术积分: 1725
  • 用 户 组: 普通用户
  • 注册时间: 2008-08-22 10:36
文章分类

全部博文(147)

文章存档

2011年(1)

2010年(1)

2009年(35)

2008年(110)

我的朋友

分类: Java

2009-02-04 21:36:34

1 为什么要使用JAXB

Java Architecture for XML Binding (JAXB)


在Java中处理XML数据的常规方法有SAX,DOM等。其中SAX使用起来很麻烦,不能修改 XML数据;而DOM的处理大文档速度非常的慢,易用性也不必SAX好到哪里去。实际上,无论是SAX还是DOM都不是专门为Java准备的,它们都是访 问XML文档的统一底层接口,与语言无关。
现在我们有了另外的选择。这就是JAXB和JDOM。JDOM与本文无关,目前最新的版本是beta8,感兴趣的话,可以访问。
JAXB 的全名是Java ™ Architecture for XML Binding,目前是1.0的early access版本,在Sun的Java站 点只有注册为成员才能够下载。JAXB的特点就是将你用DTD定义好的XML文档映射为Java对象,提供简单、快速的数据操作方式。要访问XML中的元 素、属性只要通过相应对象上的一系列getter和 setter方法。你还可以通过marshal方法将对象的数据写进XML文件,通过 unmarshal方法将XML文件的数据读入对象,通过validate方法验证XML文件是否符合DTD的约束。JAXB的缺点就在于只能访问特定的 (也就是你用DTD定义的)XML文档。

2 JAXB如何工作


JAXB包括了一个运行类库和一个模式编译器。 首先你要定义XML的DTD,然后编写一个绑定模式(Binding Schema)。DTD定义了XML文档,绑定模式也是一个XML文件,指出DTD 定义的XML文档如何被映射为Java对象。运行编译器,将DTD和绑定模式作为参数传给编译器,编译器就会生成Java代码。编译生成的Java代码, 通过这些代码就可以访问XML文档了。

3 JAXB的安装


以1.0 early access为例,它不包含 在JDK中,先到下载。注意由于是早期版本,需要先登录才能下载,本文附带的源码包含了 JAXB1.0 early access。下载后将文件解压缩,在lib目录中有两个文件。jaxb-rt-1.0-ea.jar是运行支持库, jaxb-xjc-1.0-ea.jar是模式编译器。注意bin目录中的xjc文件只能在UNIX下使用,如果你的系统是Windows,那么你需要在 命令行窗口手工输入命令来编译。为了在任何地方都可以运行模式编译器和它生成的代码,我们要把这两的文件加入CLASSPATH。一个简单的办法是把这两 个文件拷贝到jre/lib/ext下。

4 一个简单的例子


有这样一个XML文档。它描述书的列表,举例如下:

  1. //exampleA.xml

  2. "1.0" encoding="GBK"?>
  3.     
  4.         Java编程入门
  5.         张三
  6.         2002-6-6
  7.         35.0
  8.     
  9.     
  10.         XML在Java中的应用
  11.         李四
  12.         2002-9-16
  13.         92.0
  14.     

其DTD文件如下:

  1. //bookList.dtd


现在我们就来编写一个最简单的绑定模式,其文件扩展名应该为xjs。

  1. //bookList.xjs

  2. "1.0-ea">
  3.     "bookList" type="class" root="true"/>

现在就可以运行模式编译器生成Java代码,请先保证CLASSPATH中包含了JAXB的两个JAR文件。Windows用户注意bin目录下的那个文件是没用的。在命令行运行:
  1. java com.sun.tools.xjc.Main bookList.dtd bookList.xjs

如果没出问题,编译器就生成了Book.java,BookList.java两个文件。你不用去理解这两个源文件里面的代码,只要知道怎么使用它们提供的方法就可以了。它们的继承结构都是这样的:

  1. java.lang.
  2.    javax.xml.bind.ValidatableObject
  3.       javax.xml.bind.MarshallableObject
  4.          javax.xml.bind.MarshallableRootElement
  5.                 BookList or Book

BookList.java主要包含了以下方法

  1. BookList()    //构造函数
  2. List getBook()//得到书的集合,List中的对象实际类型是Book,可以添加、修改、删除其中的元素
  3. void deleteBook()   //删除集合
  4. void emptyBook()    //删除并生成一个新的空集合
  5. void marshal(X)      //将数据写进XML文档
  6. void unmarshal(X)   //将数据从XML文档读入对象
  7. void validate(X)    //检查是否符合DTD约束,同时检查子树。在这个例子中就是BookList的Book集合
  8. void validateThis()   //检查是否符合DTD约束,不检查子树

其中marshal,unmarshal,validate被重载,有多种参数形式(可以参考JAXB的API文档)。


Book.java主要包含了以下方法

  1. Book()
  2.  getName()
  3.  getAuthor()
  4.  getPublishDate()
  5.  getPrice()
  6. void setName( x)
  7. void setAuthor( x)
  8. void setPublishDate( x)
  9. void setPrice( x)
  10. void marshal()
  11. void unmarshal()
  12. void validate()

现在我们就可以使用这两个文件访问XML了。首先编译这两个文件。编写一个Test.java文件,把它和生成 的两个文件以及前面的exampleA.xml放在一起。这个程序从 exampleA.xml读入数据,作修改(把第一本书作者改成王五)后写入 exampleB.xml。因为中文的编码问题,所以我们需要多一点手续。

  1. //Test.java

  2. import java.io.*;
  3. import java.util.*;
  4. import javax.xml.bind.*;
  5. import javax.xml.marshal.*;
  6. public class Test{
  7. public static void main([] args) throws {
  8.         BookList bl = new BookList();
  9.          fis = new ("exampleA.xml");
  10.         try{
  11.             bl = bl.unmarshal(fis);
  12.         }finally{
  13.             fis.close();
  14.         }
  15.          books = bl.getBook();
  16.         Book b = (Book)books.get(0);
  17.         b.setAuthor("王五");

  18.         bl.validate();  //先验证,不然marshal会出错
  19.          fos = new ("exampleB.xml");
  20.         XMLWriter xw = new XMLWriter(fos,"GBK");
  21.         try{
  22.             bl.marshal(xw);
  23.         }finally{
  24.             fos.close();
  25.         }
  26. }
  27. }

编译运行,生成的文件exampleB.xml如下:

  1. "1.0" encoding="GBK"?>

  2.   
  3.     Java编程入门
  4.     王五
  5.     2002-6-6
  6.     35.0
  7.   
  8.     XML在Java中的应用
  9.     李四
  10.     2002-9-16
  11. 92.0

5 更进一步:数据类型转换


你可能已经注意到在上面的例子中,生成的Book对象的 getPrice方法返回的是String,实际上它应该是float。同样publishDate以该是日期类型,而不是字符串。这是因为我们的绑定模 式写得太简单了,模式编译器生成了默认的String类型。现在我们这样写:

  1. //bookList2.xjs

  2. "1.0-ea">
  3.     "bookList" type="class" root="true"/>
  4.     "price" type="value" convert="float"/>
  5.     "publishDate" type="value" convert="TransDate" />
  6.     "TransDate" type="java.util.Date"
  7.          parse="TransDate.parseDate" print="TransDate.printDate"/>

用java com.sun.tools.xjc.Main bookList.dtd bookList2.xjs运行编译器。生成的Book文件的相应代码为:

  1. float getPrice()
  2. java.util. getPublishDate()

bookList2.xjs第3行将Price转换成了float类型,float类型是一个简单类型,因此用 convert="float"描述就可以了。而 publishDate需要转变成java.util.Date,这是一个类,而且他没有以字符串作为 参数的构造函数。parse="TransDate.parseDate"就表示使用unmarshal读取数据的时候,会调用 TransDate.parseDate()方法。这个静态方法以字符串为参数,返回java.util.date。print= "TransDate.printDate"的作用相反。TransDate这个类需要我们提供。

  1. //TransDate.java

  2. import java.util.;
  3. public class TransDate {
  4.     private static java.text. df 
  5.      = new java.text.("yyyy-MM-dd");

  6.     public static  parseDate( d) {
  7.     try {
  8.         return df.parse(d);
  9.       } catch (java.text. pe) {
  10.         .out.print(pe);
  11.         return new ();
  12.     }
  13.     }

  14.     public static  printDate( d) {
  15.     return df.format(d);
  16.     }
  17. }

6 那些使JAXB能够做到,但本文没有提到的


本文提供的这个例子很简单,实际上JAXB还可以定义文档的哪些元素(属性)可以被转换成类,哪些被转换成类的属性。处理元素的属性。处理枚举值。为一些元素共同的子元素生成接口(因为JAXB不支持NameSpace),定义继承结构等等。

7 JAXB不能做到的


Sun的文档里提到的:
仅支持用DTD定义XML
不支持NameSpace
不支持内部子集、NOTATIONs、ENTITY、ENTITIES等。

另外,我发现如果要写一条处理指令到XML文档中,例如指定转换的样式单

在JAXB 中好像做不到,在javax.xml.marshal.XMLWriter中有一个chars(String str)方法,可以把字符串到XML文件的 声明后面,但是这个方法对特殊字符作了转义,也就是没办法可以做到。这很奇怪,因为这是一个常用的功能,要实现也不难。也许还有我没有发现的办法。倒是有 一个doctype方法可以写DOCTYPE声明。
阅读(8310) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~