XStream簡單介紹

在轉載之前,有一些第三方的jar包是必須導入的:     
xstream-1.4.1.jar --必須的

kxml2-2.3.0.jar     --如果沒有這個的話,在執行PrintWriter instance = new PrintWriter(path);是會拋出異常的

kXML2 is a very fast XML pull-parser implementation

轉載:http://www.blogjava.net/zlkn2005/archive/2005/12/16/24240.html

XStream

 

使用 XStream 的初衷

 

研究和使用 XStream 的原因是我在項目中的一個預研。在項目中需要應用到對 XML 文件的管理和配置,因此需要一個能夠將對象保存爲 XML 的工具庫,在這裏有多種方法實現,我也研究並進行了比對,比如與 Zeus 工具的比對,與 Java 自身的 XML 工具庫的比對等。在這裏,我就描述下我的 XStream 學習過程和研究結果。

 

XStream 簡單介紹

 

XStream 是一個開源項目,一套簡單實用的類庫,用於序列化對象與 XML 對象之間的相互轉換。將 XML 文件內容解析爲一個對象或將一個對象序列化爲 XML 文件。

XStream 可以用於 JDK1.3 以上的版本使用,我是在 JDK1.5 下使用它的。

XStream 的相關信息可以到 http://xstream.codehaus.org/ 下查看,它有專門的 JavaDoc ,可以方便的閱讀Xstream 的函數及方法。

XStream 中主要的類爲 XStream ,它用於序列化對象與 XML 對象之間的相互轉換。簡單的使用它就可以解決很多問題。

XStream 中主要的方法也是我用的比較多的是 fromXML() 和 toXML() 。

fromXML 用於從 XML 中將對象解析出來。

toXML 用於將對象序列化爲 XML 文件。

在 XStream 中我還使用 HierarchicalStreamWriter , HierarchicalStreamReader ,createObjectInputStream() , createObjectOutputStream() ,主要是用於對象的輸入輸出。

下面我們來研究下 XStream 的工作方式。

 

XStream 的實例——將一個序列化對象轉化爲 XML 對象。

 

一,創建 XStream 對象。

XStream xstream=new XStream();

用默認構造器構造了一個名爲 xstream 的 XStream 的對象。默認構造器所使用 XML 解析庫爲 Xpp3 庫,XPP3 是一種運行效率非常高的 XML 全解析實現。

 

二,創建需要序列化的對象。

比如這個類就叫 PrintUnit 。

構造也比較簡單,一個簡單的 JavaBean

       public class PrintUnit

       {

              Private String a;

              Private String b;

              Private String c;

             

              Public PrintUnit(){}

             

              Public setA(String a)

              {

                     this.a=a;

              }

 

              Public getA()

              {

                     return a;

              }

 

              Public setB(String b)

              {

                     this.b=b;

              }

 

              Public getB()

              {

                     return b;

              }

 

              Public setC(String c)

              {

                     This.c=c;

              }

 

              Public getC()

              {

                     Return c;

              }

       }

 

在例子中使用這個 JavaBean 。

創建並初始化 PrintUnit 。

PrintUnit pu=new PrintUnit();

pu.setA("A11");

pu.setB("B22");

pu.setC("C33");

 

三,創建 Writer 。

創建一個輸出流,至於怎麼輸出我發現可以使用多種方法,其實原理是一樣的。

在這裏就不得不提到 HierarchicalStreamWriter,HierarchicalStreamWriter 是一個接口,從字面上意思來說它是有等級的輸入流。同樣在 XStream 中也有不少這個接口的實現類用於輸出。我現在所用過的有 CompactWriter和 PrettyPrintWriter 這 2 個。

我是這樣做的:

String str="stream.xml"; // 本目錄下的一個名爲 stream 的 XML 文件

PrintWriter pw=new PrintWriter(str);// 創建一個 PrintWriter 對象,用於輸出。

之後選用一個 HierarchicalStreamWriter 的實現類來創建輸出。

選用 CompactWriter 創建:

CompactWriter cw=new CompactWriter(pw);

選用 PrettyPrintWriter 創建:

PrettyPrintWriter ppw=new PrettyPrintWriter(pw);

兩者所使用的方法都是很簡單的。

CompactWriter 與 PrettyPrintWriter 的區別在於,以 CompactWriter 方法輸出的爲連續的沒有分隔的 XML 文件,而用 PrettyPrintWriter 方法輸出的爲有分隔有一定格式的 XML 文件。

以 CompactWriter 方式生成的 XML 文件:

 

<object-stream><PrintUnit><a>A11</a><b>B22</b><c>C33</c></PrintUnit></object-stream>

 

以 PrettyPrintWriter 方式生成的 XML 文件:

       <object-stream>

             <PrintUnit>

                   <a>A11</a>

                  <b>B22</b>

                  <c>C33</c>

             </PrintUnit>

       </object-stream>

 

       我想大家能很容易的分辨出它們的差異。

 

       四,輸出操作       

以上步驟完成後就可以做輸出操作了, XStream 的輸出方式有多種: toXML 方式, ObjectOutputStream 方式, marshal 方式以及一些我尚未發現的一些其它方式。

先說下我所使用的方式它們各自的不同點,從工作原理上說它們是相似的,但是做法各不相同。

toXML() 方法,本身 toXML 的方法就有 2 種:

第一種 :java.lang.String toXML(java.lang.Object obj)

將對象序列化爲 XML 格式並保存到一個 String 對象中。

第二種 :void toXML(java.lang.Object obj, java.io.Writer out)

將對象序列化爲 XML 格式後以 Writer 輸出到某個地方存儲。

我所使用的是第二種方式,使用前面已經做好的 Pw 就可以實現輸出,它其實很簡單不需要再去做其它定義,只需要一個 PrintWriter 對象和需要序列化的 Object 即可。

直接調用 xstream.toXML(printUnit,pw); 就能輸出 XML 文件 , 在這裏是輸出到該目錄下的 stream.xml 中。這裏的輸出都是覆蓋性的,不是末尾添加形式。

使用 ObjectOutputStream 方式,簡單說它就是生成一個對象輸出流。

ObjectOutputStream obj_out = xstream.createObjectOutputStream(ppw);

使用 XStream 的 createObjectOutputStream 方法創建一個 ObjectOutputStream 對象,用於 XML 的輸出。這裏使用的是 PrettyPrintWriter 的方式。    之後調用 writerObject 方法既可,使用方法與其它輸出流類似。

obj_out.writeObject(pu);

obj_out.close();

使用 marshal 方式,其實 marshal 方法和 toXML 方法是相同的。在調用 toXML 方法進行輸出時,在XStream 內部是需要調用 marshal 方法的,然後它再去調用對象 marshallingStrategy 的 marshal 方法。所以做toXML 其實和 marshal 是相同的,在這裏只是想更加說明它的工作方式。

 

使用 void marshal(java.lang.Object obj, HierarchicalStreamWriter writer) 方法。

延續上面的例子,在這裏可以這樣寫: xstream.marshal(pu,ppw);

 

需要注意的是,和 toXML 不同的是參數,一個是 PrintWriter 對象一個則是 PrettyPrintWriter 對象。因爲marshal 中需要

 

HierarchicalStreamWriter ,而 PrettyPrintWriter 則是實現了 HierarchicalStreamWriter 接口的實現類。

 

結果和 toXML 是相同的。

 

五,結果:

       <object-stream>

             <PrintUnit>

                   <a>A11</a>

                   <b>B22</b>

                  <c>C33</c>

             </PrintUnit>

       </object-stream>

 

經過以上 5 步的操作既可將一個序列化對象轉化爲 XML 對象。

 

 

XStream 的實例——將 XML 文件轉化爲一個對象

 

通過上面的一個例子不難看出 XStream 簡便性,既然有了輸出就一定會有輸入。

輸入方我們將會使用 ObjectInputStream 。

與輸出相同我們需要有一個 XStream 對象,暫且名爲 xstream 。之後需要讀取的 XML 文件地址目錄信息。沿用上面的例子。

String inputStr="xstream.xml";

XStream xstream=new XStream();

我們需要通過對象流進行輸入操作,所以需要 FileReader 和 BufferedReader 。

FileReader fr=new FileReader(inputStr);

BufferedReader br=new BufferedReader(fr);

創建對象輸入流

ObjectInputStream obj_input=xstream.createObjectInputStream(br);

創建對象,還是使用 PrintUnit 這個對象。

PrintUnit pu2;

通過 ObjectInputStream 中的 readObject() 方法將對象從 XML 文件中讀取出來。

pu2=(PrintUnit)obj_input.readObject();

獲取值:

System.out.println(pu2.getB());

控制檯:

B22 

 

從整個輸入的過程來看,是一個文件的讀取,將其中的對象數據取出來,然後再對這個對象數據進行操作。內容也比較簡單通過 ObjectInputStream 輸入對象。

通過以上的輸入輸出例子,我想大家應該很容易就能理解 XStream 是如何實現的。

 

FomXML

 

上面使用的是以 ObjectInputStream 的方式進行 XML 與對象之間進行轉換的。下面我將使用 XStream 中的fromXML ()方法進行轉換。

首先在使用 fromXML 我發現一個問題,它必須使用正確的解析方式或輸出方式對應的輸入方式纔可以正常解析讀取文件,這個問題有點怪,不過確實存在,當我使用前面 ObjectOutputStream 方式輸出的 XML 文件 , 用fromXML ()解析讀取時,它會報錯。

錯誤信息:

Exception in thread "main" com.thoughtworks.xstream.alias.CannotResolveClassException: object$stream : object$stream

信息內容爲:不能解析這個文件。我認爲它和輸出方式有關,因爲上面例子中使用的是 ObjectOutputStream,當我反過來做了一個實驗後也證明了這一點。

實驗大致內容:使用 toXML() 方法輸出 XML 文件,使用 ObjectInputStream 解析,發現會在讀取的時候拋出CannotResolveClassException 異常。

錯誤信息:

Exception in thread "main" com.thoughtworks.xstream.alias.CannotResolveClassException:

a : a

       因此我認爲在解析文件的時候必須先要確定這個文件是由什麼方式生成的,然後在解析它,對於使用Dom,Dom4j,XPP 等不同方式解析尚未嘗試。以上測試是在默認的基礎上實驗的,默認爲 XPP3 的解析器。

 

       使用 fromXML 的方法。

      

       public java.lang.Object fromXML(java.lang.String xml)

       public java.lang.Object fromXML(java.io.Reader xml)

public java.lang.Object fromXML(java.lang.String xml,java.lang.Object root)

public java.lang.Object fromXML(java.io.Reader xml,java.lang.Object root)

      

例子:

       PrintUnit puTwo=(PrintUnit)xstream.fromXML(xml);

      

這裏的 xml 必須是使用 toXML() 生成出來的。對於 Reader 沒有太多的要求。

 

 

XStream 與 Java.Bean 中 XML 工具的比較

 

       XStream 主要作用是將序列化的對象轉化爲一個 XML 文件或將 XML 文件解析爲一個對象。當然並非只有它可以做到,很多其它工具一樣可以,在 Java 中存在這樣兩個類 XMLDecoder 和 XMLEncoder ,它們是在Java.Bean 包下的,它們的作用是將 JavaBean 轉化爲 XML 或將 XML 文件轉化爲一個 Java Bean 。

       XMLDecoder 是通過一個輸入流將對象從輸入流中取出並轉化爲一個實例的方法。它所需要的就是一個輸入流及一個轉化過程。

 

       XMLDecoder 的實例:

 

       String fileStr=”xstream.xml”;//XML 文件,在本目錄下,延用上次使用文件。

       ObjectInputStream in=new ObjectInputStream(new FileInputStream(fileStr));// 創建一個 ObjectInputStream用於輸入。

       XMLDecoder xmld=new XMLDecoder(in);// 創建一個 XMLDecoder 對象。

       延用前面所使用 PrintUnit 這個 Bean 。

       PrintUnit pu=(PrintUnit)xmld.readObject();// 通過 XMLDecoder 中的 readObject 方法獲得 PrintUnit 對象。

如果獲取到了這個對象那麼 pu 中將有它的值 a=A11,b=B22,c=C33 。整個過程最好放 try

…catch 中去,能夠捕獲一些如:文件不存在等異常。

       從操作方式上看 XMLDecoder 似乎不比 XStream 差多少,同樣是可以通過 ObjectInputStream 獲取 XML 文件中的對象。它們的差異就是解析的方式不同, XMLDecoder 是使用 Java 自帶的 XML 解析方式,而 XStream 則是可以自定義的,它可以使用多中方式進行解析。這些是我個人所發現的一些不同點。

 

       XMLEncoder 是通過一個輸出流將對象序列化並輸出爲 XML 文件。它所需要的是一個輸出流及一個輸出方式。

 

       XMLEncoder 的實例:

 

       String fileStr=”xstream.xml”;// 定義一個輸入的目標文件。

       ObjectOutputStream out=new ObjectOutputStream(new FileOutputStream(fileStr));// 創建一個對象輸出流。

       XMLEncoder xmle=new XMLEncoder(out);// 創建一個 XMLEncoder 對象。

       延用前面所使用 PrintUnit 這個 Bean 。

// 創建並初始化 PrintUnit 對象。

PrintUnit pu=new PrintUnit();

pu.setA(“AAA”);

pu.setB(“BBB”);

pu.setC(“CCC”);

 

       xmle.writeObject(pu);// 使用 XMLEncode 的 writeObject 方法輸出 pu

       xmle.flush();// 刷新

       xmle.close();// 關閉輸出流

 

       從上面的代碼不難看出,使用 XMLEncode 方式將對象序列化並輸出也是很方便的,簡單調用 writeObject 方法能將普通 Bean 輸出爲 XML 文件。

      

       XML 文件的內容:

 

�_ <? xml version = "1.0" encoding = "UTF-8" ?>

< java version = "1.5.0" class = "java.beans.XMLDecoder" >

  < object class = "test.PrintUnit" >

  < void property = "a" >

   < string > AAA </ string >

  </ void >

  < void property = "b" >

   < string > BBB </ string >

  </ void >

  < void property = "c" >

   < string > CCC </ string >

  </ void >

  </ object >

w   </java>

 

       不知道是我哪裏沒有處理,還是實際並不是像我想象的哪麼簡單,使用 XMLEncoder 所輸出的 XML 文件中有一定的問題,雖然它很詳細,比起 XStream 所生成的更多,包括了 XML 和 Java 的版本看上去更像是個完整的XML 文件,不過再細看它們兩生成的 XML 格式內容,完全不同,這個我想就是它們最大的區別。這讓我想到了很多內容:工作方式,解析器,轉換方式等。大家有沒發現在開始和結束都存在一些亂碼數據,難道在 XMLEncoder輸出過程中或數據轉換中內容已經存在“髒”數據了?還是我所使用的輸出方式存在問題?哎 … 一個又一個問題出現了。我想我需要再進一步的研究和學習才能得到答案。

       不過儘管有這個那個的問題,使用 Java 本身自帶的 XML 工具還是一樣很實用的,讀取和輸出一樣可用,操作也很靈活。因此我覺得在某些場合使用特定的工具可能會更好,利用 XMLEncoder 和 XMLDecoder 同樣可以解決一些問題。

我的這個使用 XMLDecoder 和 XMLEncoder 的序列化格式輸出暫研究到這裏。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章