weidagang2046的專(zhuān)欄

          物格而后知致
          隨筆 - 8, 文章 - 409, 評(píng)論 - 101, 引用 - 0
          數(shù)據(jù)加載中……

          使用JAXB處理XML文檔――先睹為快

          JAXB以其方便的XML數(shù)據(jù)處理能力可能會(huì)引起你的興趣。你可能還不了解JAXB是什么,想要知道它到底有什么好處,如果這是你需要的,你才會(huì)再花時(shí)間去細(xì)細(xì)的研究它,或者你只需要使用最基本的功能。然而Sun關(guān)于JAXB的文檔有80頁(yè)之多。我想大部分人都沒(méi)有耐心看完這樣的長(zhǎng)篇大論。本文以簡(jiǎn)短的篇幅介紹了JAXB的基本使用,算是先睹為快吧。本文附帶的代碼包括了JAXB1.0 early access版本和本文所使用的代碼。歡迎與我討論: mailto:boyofjava@sina.com

           

          本文假設(shè)你會(huì)使用Java編程,了解并能夠看懂XMLDTD

           

          1 為什么要使用JAXB

          Java中處理XML數(shù)據(jù)的常規(guī)方法有SAXDOM等。其中SAX使用起來(lái)很麻煩,不能修改XML數(shù)據(jù);而DOM的處理大文檔速度非常的慢,易用性也不必SAX好到哪里去。實(shí)際上,無(wú)論是SAX還是DOM都不是專(zhuān)門(mén)為Java準(zhǔn)備的,它們都是訪問(wèn)XML文檔的統(tǒng)一底層接口,與語(yǔ)言無(wú)關(guān)。

          現(xiàn)在我們有了另外的選擇。這就是JAXBJDOMJDOM與本文無(wú)關(guān),目前最新的版本是beta8,感興趣的話,可以訪問(wèn)http://www.jdom.org/

          JAXB的全名是Java ? Architecture for XML Binding,目前是1.0early access版本,在SunJava站點(diǎn)只有注冊(cè)為成員才能夠下載。JAXB的特點(diǎn)就是將你用DTD定義好的XML文檔映射為Java對(duì)象,提供簡(jiǎn)單、快速的數(shù)據(jù)操作方式。要訪問(wèn)XML中的元素、屬性只要通過(guò)相應(yīng)對(duì)象上的一系列getter setter方法。你還可以通過(guò)marshal方法將對(duì)象的數(shù)據(jù)寫(xiě)進(jìn)XML文件,通過(guò)unmarshal方法將XML文件的數(shù)據(jù)讀入對(duì)象,通過(guò)validate方法驗(yàn)證XML文件是否符合DTD的約束。JAXB的缺點(diǎn)就在于只能訪問(wèn)特定的(也就是你用DTD定義的)XML文檔。

           

          2 JAXB如何工作

          JAXB包括了一個(gè)運(yùn)行類(lèi)庫(kù)和一個(gè)模式編譯器。首先你要定義XMLDTD,然后編寫(xiě)一個(gè)綁定模式(Binding Schema)。DTD定義了XML文檔,綁定模式也是一個(gè)XML文件,指出DTD定義的XML文檔如何被映射為Java對(duì)象。運(yùn)行編譯器,將DTD和綁定模式作為參數(shù)傳給編譯器,編譯器就會(huì)生成Java代碼。編譯生成的Java代碼,通過(guò)這些代碼就可以訪問(wèn)XML文檔了。

           

          3 JAXB的安裝

          1.0 early access為例,它不包含在JDK中,先到http://java.sun.com/xml下載。注意由于是早期版本,需要先登錄才能下載,本文附帶的源碼包含了JAXB1.0 early access。下載后將文件解壓縮,在lib目錄中有兩個(gè)文件。jaxb-rt-1.0-ea.jar是運(yùn)行支持庫(kù),jaxb-xjc-1.0-ea.jar是模式編譯器。注意bin目錄中的xjc文件只能在UNIX下使用,如果你的系統(tǒng)是Windows,那么你需要在命令行窗口手工輸入命令來(lái)編譯。為了在任何地方都可以運(yùn)行模式編譯器和它生成的代碼,我們要把這兩的文件加入CLASSPATH。一個(gè)簡(jiǎn)單的辦法是把這兩個(gè)文件拷貝到jre/lib/ext下。

           

          4 一個(gè)簡(jiǎn)單的例子

          有這樣一個(gè)XML文檔。它描述書(shū)的列表,舉例如下:

          文件exampleA.xml

          <?xml version="1.0" encoding="GBK"?>

          <bookList>

              <book>

                  <name>Java編程入門(mén)</name>

                  <author>張三</author>

                  <publishDate>2002-6-6</publishDate>

                  <price>35.0</price>

              </book>

              <book>

                  <name>XMLJava中的應(yīng)用</name>

                  <author>李四</author>

                  <publishDate>2002-9-16</publishDate>

                  <price>92.0</price>

              </book>

          </bookList>

           

          DTD文件如下:

          文件bookList.dtd

          <!ELEMENT bookList (book)*>

          <!ELEMENT book(name,author,publishDate,price)>

          <!ELEMENT name (#PCDATA)>

          <!ELEMENT author (#PCDATA)>

          <!ELEMENT publishDate (#PCDATA)>

          <!ELEMENT price (#PCDATA)>

           

          現(xiàn)在我們就來(lái)編寫(xiě)一個(gè)最簡(jiǎn)單的綁定模式,其文件擴(kuò)展名應(yīng)該為xjs

          文件bookList.xjs

          <xml-java-binding-schema version="1.0-ea">

              <element name="bookList" type="class" root="true"/>

          </xml-java-binding-schema>

           

          現(xiàn)在就可以運(yùn)行模式編譯器生成Java代碼,請(qǐng)先保證CLASSPATH中包含了JAXB的兩個(gè)JAR文件。Windows用戶(hù)注意bin目錄下的那個(gè)文件是沒(méi)用的。在命令行運(yùn)行:

          java com.sun.tools.xjc.Main bookList.dtd bookList.xjs

          如果沒(méi)出問(wèn)題,編譯器就生成了Book.javaBookList.java兩個(gè)文件。你不用去理解這兩個(gè)源文件里面的代碼,只要知道怎么使用它們提供的方法就可以了。它們的繼承結(jié)構(gòu)都是這樣的:

          java.lang.Object

             javax.xml.bind.ValidatableObject

                javax.xml.bind.MarshallableObject

                   javax.xml.bind.MarshallableRootElement

                          BookList or Book

           

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

          BookList()    //構(gòu)造函數(shù)

          List getBook()    //得到書(shū)的集合,List中的對(duì)象實(shí)際類(lèi)型是Book,可以添加、修改、刪除其中的元素

          void deleteBook()   //刪除集合

          void emptyBook()    //刪除并生成一個(gè)新的空集合

          void marshal(X)      //將數(shù)據(jù)寫(xiě)進(jìn)XML文檔

          void unmarshal(X)   //將數(shù)據(jù)從XML文檔讀入對(duì)象

          void validate(X)    //檢查是否符合DTD約束,同時(shí)檢查子樹(shù)。在這個(gè)例子中就是BookListBook集合

          void validateThis()   //檢查是否符合DTD約束,不檢查子樹(shù)

          其中marshalunmarshalvalidate被重載,有多種參數(shù)形式(可以參考JAXBAPI文檔)。

           

           

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

          Book()

          String getName()

          String getAuthor()

          String getPublishDate()

          String getPrice()

          void setName(String x)

          void setAuthor(String x)

          void setPublishDate(String x)

          void setPrice(String x)

          void marshal()

          void unmarshal()

          void validate()

           

          現(xiàn)在我們就可以使用這兩個(gè)文件訪問(wèn)XML了。首先編譯這兩個(gè)文件。編寫(xiě)一個(gè)Test.java文件,把它和生成的兩個(gè)文件以及前面的exampleA.xml放在一起。這個(gè)程序從 exampleA.xml讀入數(shù)據(jù),作修改(把第一本書(shū)作者改成王五)后寫(xiě)入exampleB.xml。因?yàn)橹形牡木幋a問(wèn)題,所以我們需要多一點(diǎn)手續(xù)。

          文件Test.java

          import java.io.*;

          import java.util.*;

          import javax.xml.bind.*;

          import javax.xml.marshal.*;

          public class Test{

                 public static void main(String[] args) throws Exception{

                  BookList bl = new BookList();

                  FileInputStream fis = new FileInputStream("exampleA.xml");

                  try{

                      bl = bl.unmarshal(fis);

                  }finally{

                      fis.close();

                  }

                  List books = bl.getBook();

                  Book b = (Book)books.get(0);

                  b.setAuthor("王五");

           

                  bl.validate();  //先驗(yàn)證,不然marshal會(huì)出錯(cuò)

                  FileOutputStream fos = new FileOutputStream("exampleB.xml");

                  XMLWriter xw = new XMLWriter(fos,"GBK");

                  try{

                      bl.marshal(xw);

                  }finally{

                      fos.close();

                  }

                 }

          }

           

          編譯運(yùn)行,生成的文件exampleB.xml如下:

          <?xml version="1.0" encoding="GBK"?>

           

          <bookList>

            <book>

              <name>Java編程入門(mén)</name>

              <author>王五</author>

              <publishDate>2002-6-6</publishDate>

              <price>35.0</price></book>

            <book>

              <name>XMLJava中的應(yīng)用</name>

              <author>李四</author>

              <publishDate>2002-9-16</publishDate>

          <price>92.0</price></book></bookList>

           

          5 更進(jìn)一步:數(shù)據(jù)類(lèi)型轉(zhuǎn)換

          你可能已經(jīng)注意到在上面的例子中,生成的Book對(duì)象的getPrice方法返回的是String,實(shí)際上它應(yīng)該是float。同樣publishDate以該是日期類(lèi)型,而不是字符串。這是因?yàn)槲覀兊慕壎J綄?xiě)得太簡(jiǎn)單了,模式編譯器生成了默認(rèn)的String類(lèi)型。現(xiàn)在我們這樣寫(xiě):

          文件bookList2.xjs

          <xml-java-binding-schema version="1.0-ea">

              <element name="bookList" type="class" root="true"/>

              <element name="price" type="value" convert="float"/>

              <element name="publishDate" type="value" convert="TransDate" />

              <conversion name="TransDate" type="java.util.Date"

                      parse="TransDate.parseDate" print="TransDate.printDate"/>

          </xml-java-binding-schema>

           

          java com.sun.tools.xjc.Main bookList.dtd bookList2.xjs運(yùn)行編譯器。生成的Book文件的相應(yīng)代碼為:

          float getPrice()

          java.util.Date getPublishDate()

           

          bookList2.xjs3行將Price轉(zhuǎn)換成了float類(lèi)型,float類(lèi)型是一個(gè)簡(jiǎn)單類(lèi)型,因此用convert="float"描述就可以了。而 publishDate需要轉(zhuǎn)變成java.util.Date,這是一個(gè)類(lèi),而且他沒(méi)有以字符串作為參數(shù)的構(gòu)造函數(shù)。parse="TransDate.parseDate"就表示使用unmarshal讀取數(shù)據(jù)的時(shí)候,會(huì)調(diào)用TransDate.parseDate()方法。這個(gè)靜態(tài)方法以字符串為參數(shù),返回java.util.dateprint="TransDate.printDate"的作用相反。TransDate這個(gè)類(lèi)需要我們提供。

          文件TransDate.java

          import java.util.Date;

          public class TransDate {

              private static java.text.SimpleDateFormat df

                     = new java.text.SimpleDateFormat("yyyy-MM-dd");

           

              public static Date parseDate(String d) {

                     try {

                         return df.parse(d);

                    } catch (java.text.ParseException pe) {

                         System.out.print(pe);

                         return new Date();

                     }

              }

           

              public static String printDate(Date d) {

                     return df.format(d);

              }

          }

           

          6 那些使JAXB能夠做到,但本文沒(méi)有提到的

          本文提供的這個(gè)例子很簡(jiǎn)單,實(shí)際上JAXB還可以定義文檔的哪些元素(屬性)可以被轉(zhuǎn)換成類(lèi),哪些被轉(zhuǎn)換成類(lèi)的屬性。處理元素的屬性。處理枚舉值。為一些元素共同的子元素生成接口(因?yàn)?/SPAN>JAXB不支持NameSpace),定義繼承結(jié)構(gòu)等等。

           

          7 JAXB不能做到的

          Sun的文檔里提到的:

          僅支持用DTD定義XML

          不支持NameSpace

          不支持內(nèi)部子集、NOTATIONsENTITYENTITIES等。

           

          另外,我發(fā)現(xiàn)如果要寫(xiě)一條處理指令到XML文檔中,例如指定轉(zhuǎn)換的樣式單

          <?xml-stylesheet href=”a.xsl” type=”text/xsl”?>

          JAXB中好像做不到,在javax.xml.marshal.XMLWriter中有一個(gè)chars(String str)方法,可以把字符串到XML文件的聲明后面,但是這個(gè)方法對(duì)特殊字符作了轉(zhuǎn)義,也就是沒(méi)辦法可以做到。這很奇怪,因?yàn)檫@是一個(gè)常用的功能,要實(shí)現(xiàn)也不難。也許還有我沒(méi)有發(fā)現(xiàn)的辦法。倒是有一個(gè)doctype方法可以寫(xiě)DOCTYPE聲明。

           

          8 參考文檔

          1 The Java ? Architecture for XML Binding User’s Guide

           (http://java.sun.com/xml/jaxb/jaxb-docs.pdf)

          2 Web Services Made Easier. The Java TM APIs and Architectures for XML, A Technical White Paper (http://java.sun.com/xml/webservices.pdf )

          轉(zhuǎn)自:http://www.csdn.com.cn/program/2823.htm

          posted on 2005-04-23 14:34 weidagang2046 閱讀(599) 評(píng)論(0)  編輯  收藏 所屬分類(lèi): XML


          只有注冊(cè)用戶(hù)登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 根河市| 绥中县| 丹阳市| 黔西| 班玛县| 东乡县| 图们市| 类乌齐县| 安化县| 林口县| 雷山县| 安新县| 白玉县| 南投市| 屏东县| 西畴县| 宜川县| 甘洛县| 南江县| 上思县| 崇州市| 盐城市| 永嘉县| 桃园市| 涟源市| 固镇县| 高碑店市| 威宁| 明溪县| 武威市| 汶上县| 乌兰浩特市| 高阳县| 舒城县| 体育| 阳谷县| 新化县| 申扎县| 冀州市| 孙吴县| 高淳县|