用Castor 處理XML文檔

用Castor 處理XML文檔 ——Castor能夠完成Java和XML的相互轉換 前面有介紹過json-lib這個框架,在線博文:http://www.cnblogs.com/hoojo/archive/2011/04/21/2023805.html 以及Jackson這個框架,在線博文:http://www.cnblogs.com/hoojo/archive/2011/04/22/2024628.html 它們均可以完成Java對象到XML的轉換,可是還不是那麼的完善。還有XStream對JSON及XML的支持,它能夠對JSON或XML的完美轉換。在線博文: http://www.cnblogs.com/hoojo/archive/2011/04/22/2025197.html 這裏將介紹Castor來完成Java對象到xml的相互轉換。它是怎麼樣轉換的?和前面不一樣的是castor能夠用一個mapping.xml文件來描述轉換後的Java對象的xml基本形態,相似於xStream的annotation,這點仍是很是不錯的。下面咱們就來看看Castor是怎麼樣完成Java對象到XML之間的相互轉換吧。 1、 準備工做 一、 官方資源 本示例會運用到以下依賴包(jar包):   資源及jar包下載:http://www.castor.org/download.html junit jar下載地址: https://github.com/KentBeck/junit/downloads 關於官方提供的mapping配置相關示例、文檔: http://www.castor.org/xml-mapping.html ibm提供的castor方面的文檔資料: http://www.google.com.hk/search?hl=zh-CN&newwindow=1&safe=strict&client=aff-cs-360se&hs=Gon&biw=1349&bih=603&q=castor+site%3Awww.ibm.com%2Fdeveloperworks%2Fcn%2Fxml%2F&aq=f&aqi=&aql=&oq= 二、 程序測試運行代碼 package com.hoo.test;   import java.io.IOException; import java.io.StringReader; import java.io.StringWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.exolab.castor.mapping.Mapping; import org.exolab.castor.mapping.MappingException; import org.exolab.castor.xml.MarshalException; import org.exolab.castor.xml.Marshaller; import org.exolab.castor.xml.Unmarshaller; import org.exolab.castor.xml.ValidationException; import org.junit.After; import org.junit.Before; import org.junit.Test; import com.hoo.entity.Account; import com.hoo.entity.AccountArray; import com.hoo.entity.Birthday; import com.hoo.entity.ListBean; import com.hoo.entity.MapBean;   /**  * <b>function:</b>Castor完成Java對象到XML的相互轉換  * 依賴jar: castor-1.3.jar  * castor-1.3-core.jar  * junit-4.8.2.jar  * log4j-1.2.16.jar  * commons-logging.jar  * @author hoojo  * @createDate 2011-4-21 下午07:57:26  * @file CastorTest.java  * @package com.hoo.test  * @project WebHttpUtils  * @blog http://blog.csdn.net/IBM_hoojo  * @email hoojo_@126.com  * @version 1.0  */ public class CastorTest {         private Account bean = null;     private Mapping mapping = new Mapping();     private StringWriter writer = null;     private StringReader reader = null;         @Before     public void init() {         bean = new Account();         bean.setAddress("北京");         bean.setEmail("email");         bean.setId(1);         bean.setName("jack");         Birthday day = new Birthday();         day.setBirthday("2010-11-22");         bean.setBirthday(day);                 try {             /**              * 加載mapping.xml,此文件是對須要轉換的Java對象的配置描述,              * 即:轉換後的Java對象的xml內容的轉換規則              */             mapping.loadMapping(System.getProperty("user.dir") + "\\src\\mapping.xml");         } catch (IOException e) {             e.printStackTrace();         } catch (MappingException e) {             e.printStackTrace();         }     }         @After     public void destory() {         bean = null;         mapping = null;         try {             if (writer != null) {                 writer.flush();                 writer.close();             }             if (reader != null) {                 reader.close();             }         } catch (IOException e) {             e.printStackTrace();         }         System.gc();     }         public void fail(Object o) {         System.out.println(o);     }         public void failRed(Object o) {         System.err.println(o);     } } Mapping對象能夠完成Java對象到XML的編組和解組,它須要先設定一個mapping.xml,經過xml對JavaObject的描述。來完成JavaObject的編組、解組工做。 三、 看看即將被轉換的JavaEntity代碼 Account package com.hoo.entity;   public class Account {     private int id;     private String name;     private String email;     private String address;     private Birthday birthday;         //setter、getter     @Override     public String toString() {         return this.id + "#" + this.name + "#" + this.email + "#" + this.address + "#" + this.birthday;     } } Birthday package com.hoo.entity;   public class Birthday {     private String birthday;         public Birthday(String birthday) {         super();         this.birthday = birthday;     }     //getter、setter     public Birthday() {}         @Override     public String toString() {         return this.birthday;     } } AccountArray package com.hoo.entity;   public class AccountArray {     private Account[] accounts;     private int size;     public int getSize() {         size = accounts.length;         return size;     }     public void setSize(int size) {         this.size = size;     }     public Account[] getAccounts() {         return accounts;     }     public void setAccounts(Account[] accounts) {         this.accounts = accounts;     } } ListBean package com.hoo.entity;   import java.util.List;   public class ListBean {     private String name;     private List list;     //setter、getter } MapBean package com.hoo.entity;   import java.util.Map;   public class MapBean {     private Map<String, Object> map;         public Map<String, Object> getMap() {         return map;     }     public void setMap(Map<String, Object> map) {         this.map = map;     } } 2、 編組JavaObject到XML 一、 將JavaBean編組,轉換成XML /**  * <b>function:</b>將Javabean編組,轉換成XML  * @author hoojo  * @createDate 2011-4-22 下午12:08:48  */ @Test public void writeBean2XML() {     writer = new StringWriter();     try {         //編組         Marshaller.marshal(bean, writer);         fail(writer);     } catch (MarshalException e) {         e.printStackTrace();     } catch (Exception e) {         e.printStackTrace();     } } 代碼很簡單,經過Marshaller的marshal方法來完成Java對象到XML的編組(序列化、轉換)工做。 運行後的結果以下: <?xml version="1.0" encoding="UTF-8"?> <account id="1"><address>北京</address><email>email</email><name>jack</name> <birthday><birthday>2010-11-22</birthday></birthday></account> 二、 將List集合轉換成XML /**  * <b>function:</b>將List轉換成xml  * @author hoojo  * @createDate 2011-4-22 下午12:11:00  */ @Test public void writeList2XML() {     writer = new StringWriter();     List<Account> list = new ArrayList<Account>();     list.add(bean);     bean = new Account();     bean.setName("tom");     bean.setId(223);     list.add(bean);     try {         Marshaller.marshal(list, writer);         fail(writer);     } catch (MarshalException e) {         e.printStackTrace();     } catch (Exception e) {         e.printStackTrace();     } } 運行後,結果以下: <?xml version="1.0" encoding="UTF-8"?> <array-list> <account xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:java="http://java.sun.com" id="1" xsi:type="java:com.hoo.entity.Account"> <address>北京</address><email>email</email><name>jack</name><birthday><birthday>2010-11-22</birthday></birthday></account> <account xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:java="http://java.sun.com" id="223" xsi:type="java:com.hoo.entity.Account"> <name>tom</name> </account> </array-list> 怎麼樣,List存放的是2個Account吧。 三、 將Array數組轉換成XML /**  * <b>function:</b>將Array數組轉換成XML  * @author hoojo  * @createDate 2011-4-22 下午12:11:25  */ @Test public void writeArray2XML() {     writer = new StringWriter();     Account[] acc = new Account[2];     acc[0] = bean;     bean = new Account();     bean.setName("tom");     bean.setId(223);     acc[1] = bean;         try {         Marshaller.marshal(acc, writer);         fail(writer);     } catch (MarshalException e) {         e.printStackTrace();     } catch (Exception e) {         e.printStackTrace();     } } 結果以下: <?xml version="1.0" encoding="UTF-8"?> <array><account id="1"><address>北京</address><email>email</email><name>jack</name> <birthday><birthday>2010-11-22</birthday></birthday></account> <account id="223"><name>tom</name></account></array> 四、 轉換其餘Java類型 /**  * <b>function:</b>將Java經常使用類型編組成xml  * @author hoojo  * @createDate 2011-4-22 下午12:11:44  */ @Test public void writeObject2XML() {     writer = new StringWriter();     try {         Marshaller.marshal(true, writer);         Marshaller.marshal(9527, writer);         Marshaller.marshal(2.2f, writer);         Marshaller.marshal(1.11d, writer);         Marshaller.marshal("lucy", writer);         Marshaller.marshal("hello castor".getBytes(), writer);         Marshaller.marshal(new char[] { 'a', 'b', 'c' }, writer);         Marshaller.marshal(new String[] { "hi", "spring", "castor" }, writer);         fail(writer);     } catch (MarshalException e) {         e.printStackTrace();     } catch (Exception e) {         e.printStackTrace();     } } 結果以下: <?xml version="1.0" encoding="UTF-8"?> <boolean>true</boolean><?xml version="1.0" encoding="UTF-8"?> <integer>9527</integer><?xml version="1.0" encoding="UTF-8"?> <float>2.2</float><?xml version="1.0" encoding="UTF-8"?> <double>1.11</double><?xml version="1.0" encoding="UTF-8"?> <string>lucy</string><?xml version="1.0" encoding="UTF-8"?> <[-b>aGVsbG8gY2FzdG9y</[-b><?xml version="1.0" encoding="UTF-8"?> <array><character>a</character><character>b</character><character>c</character></array><?xml version="1.0" encoding="UTF-8"?> <array><string>hi</string><string>spring</string><string>castor</string></array> 都是類型爲節點名稱,值爲text。可是這裏並無出現Map,若是轉換Map須要mapping進行配置。下面再慢慢道來-.- 五、 將xml解組成JavaBean /**  * <b>function:</b>將XML內容,解組成JavaBean  * @author hoojo  * @createDate 2011-4-22 下午12:12:14  */ @Test public void readXML2Bean() {         String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +                     "<account id=\"1\"><address>北京</address>" +                     "<name>jack</name><email>email</email>" +                     "<birthday><birthday>2010-11-22</birthday></birthday></account>";     reader = new StringReader(xml);         try {         //解組         Account account = (Account) Unmarshaller.unmarshal(Account.class, reader);         fail(account);     } catch (MarshalException e) {         e.printStackTrace();     } catch (ValidationException e) {         e.printStackTrace();     } } 結果以下: 1#jack#email#北京#2010-11-22 其餘的類型,如:map、list、array都不能成功解組。由於這些類型裏面有不少系統默認的xml描述。可是利用mapping和自定義JavaBean就能夠成功編組和解組了。下面看看mapping是怎麼玩轉這些類型的。 3、 利用mapping配置,編組JavaObject、解組XML 最開始的init方法就提供了mapping,讓咱們對mapping這個配置有了大概的瞭解。下面咱們將詳細介紹mapping是個什麼: 一、 在此以前咱們設置過mapping.xml。若是不設置,確定是不能轉換成咱們想要的XML的。那麼,mapping.xml配置文件是怎麼配置Account這個對象的呢? mapping.xml配置以下: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN" "http://castor.org/mapping.dtd"> <mapping>     <class name="com.hoo.entity.Account" auto-complete="true">           <map-to xml="Account"/>           <field name="id" type="integer">             <bind-xml name="id" node="attribute" />         </field>           <field name="name" type="string">             <bind-xml name="name" node="element" />         </field>           <field name="email" type="string">             <bind-xml name="email" node="element" />         </field>           <field name="address" type="string">             <bind-xml name="address" node="element" />         </field>           <field name="birthday" type="com.hoo.entity.Birthday">             <bind-xml name="生日" node="element" />         </field>     </class>       <class name="com.hoo.entity.Birthday">         <map-to xml="birthday" />           <field name="birthday" type="string">             <bind-xml name="birthday" node="attribute" />         </field>     </class> </mapping> 首先,看看這個xml文檔的根元素是mapping,在mapping中能夠配置class。也就是咱們要轉換的JavaObject的配置描述了。 class元素的name屬性就是配置的JavaObject的classpath路徑了。 關於class元素的auto-complate屬性,若是這個屬性的值爲ture。那麼編組後的xml,castor會自動給沒有在mapping配置文件進行配置的屬性自動編組(轉換)到xml中。若是爲false,那麼在mapping配置文件中出現的屬性將在編組後不如今在編組後的xml中。 map-to就是當前class編組後的xml文檔的節點元素名稱。 field就是描述JavaObject中的屬性,name是Java對象的屬性名稱,type是類型。關於配置的type類型也有規定,你能夠參考:http://www.castor.org/xml-mapping.html的field配置講解。 而field還有其餘的屬性配置,如get-method應該是getter方法、set-method應該是setter的方法、has-mehtod應該是hashCode方法,有時候咱們不必定要提升getter、setter方法,咱們須要用本身的方法名稱來代替setter、getter。若是當前field配置的是集合類型,那麼你須要給field元素配置collection屬性。 bind-xml就是綁定(編組)成xml後的xml內容的描述,name就是編組後xml的節點元素名稱,node有2個值,分別是attribute、element。attribute是屬性,它會在節點元素的屬性中顯示,例如:<account id=」2」></account> 而element則是單獨的一個元素,例如:<account><id>2</id></account> 就這個樣子的。 mapping.xml還能夠有其餘標籤,如: <include href="other_mapping_file.xml"/> 導入外部xml文件,能夠分多個配置。 好了,先將這麼多的mapping方面的內容。咱們仍是看看實際運行的示例吧,代碼以下: /**  * <b>function:</b>將XML內容解組成Java對象  * @author hoojo  * @createDate 2011-4-22 下午12:13:28  */ @Test public void bean4Mapping2XML() {     writer = new StringWriter();     try {         //編組         Marshaller mar = new Marshaller(writer);         mar.setMapping(mapping);         mar.marshal(bean);         fail(writer);                 //解組         reader = new StringReader(writer.toString());         Unmarshaller unmar = new Unmarshaller(Account.class);         unmar.setMapping(mapping);                 Account account = (Account) unmar.unmarshal(reader);         fail(account);     } catch (MarshalException e) {         e.printStackTrace();     } catch (Exception e) {         e.printStackTrace();     } } 運行後結果以下: <?xml version="1.0" encoding="UTF-8"?> <Account id="1"><name>jack</name><email>email</email><address>北京</address><生日 birthday="2010-11-22"/></Account> 1#jack#email#北京#2010-11-22 上面的xml的根節點是Account,這個功勞就來源於mapping配置中的map-to元素,而根節點的id屬性是有field和bind-xml來完成的。當bind-xml的node值爲attribute時,就會以屬性的方式顯示。當node爲element時,就會像後面name、email同樣,以元素名稱顯示。 再看看上面的mapping文件中的Account的配置,有個auto-complate屬性,若是把這個屬性的值設置成false,會怎麼樣?那咱們趕忙試試。 沒有發現上面異樣,可是當咱們刪除下面配置的filed的時候,就發現有變化了。 結果以下: <?xml version="1.0" encoding="UTF-8"?> <Account><name>jack</name><email>email</email><address>北京</address><生日 birthday="2010-11-22"/></Account> 0#jack#email#北京#2010-11-22 發現id沒有顯示在xml中,那麼咱們再將auto-complate的屬性設置true,會有什麼驚喜? 結果以下: <?xml version="1.0" encoding="UTF-8"?> <Account id="1"><name>jack</name><email>email</email><address>北京</address><生日 birthday="2010-11-22"/></Account> 1#jack#email#北京#2010-11-22 發現id又回來了,可是Account的配置中並無配置id的field。這是爲何,其實auto-comlate在上面已經講過了。Castor在編組時會自動將int類型的屬性,顯示在父元素的屬性中。而且JavaObject中有的屬性沒有在mapping配置文件中配置,castor也會自動將其編組在xml中。 下面咱們看看map-to配置的用法,map-to的主要屬性是name,也就是咱們把當前根元素重命名的名稱。Map-to還有2個屬性能夠用,分別是ns-uri、ns-prefix。看名稱就知道它大概的意識,一個是命名空間的uri另外一個則是命名空間的前綴。咱們給上面mapping加上這兩個屬性看看。 <map-to xml="Account" ns-uri="http://hoojo.cnblogs.com" ns-prefix="castor"/> 結果以下: <?xml version="1.0" encoding="UTF-8"?> <castor:Account xmlns:castor="http://hoojo.cnblogs.com" id="1"><castor:name>jack</castor:name><castor:email>email</castor:email> <castor:address>北京</castor:address><castor:生日 birthday="2010-11-22"/></castor:Account> 1#jack#email#北京#2010-11-22 發現了什麼?節點元素都帶上了ns-prefix的值,而根元素則有了xml的ns。 二、 將一段XML格式字符串轉換成JavaBean @Test public void readBean4Mapping2XML() {     String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +                 "<Account id=\"2241\"><name>jack</name><email>email</email><address>北京</address><生日 birthday=\"2010-11-22\"/></Account>";     try {         reader = new StringReader(xml);         Unmarshaller unmar = new Unmarshaller(Account.class);         unmar.setMapping(mapping);                 Account account = (Account) unmar.unmarshal(reader);         fail(account);     } catch (MarshalException e) {         e.printStackTrace();     } catch (Exception e) {         e.printStackTrace();     } } 運行後結果以下: 2241#jack#email#北京#2010-11-22 三、 將XML內容解組成Java的Array /**  * <b>function:</b>將XML內容解組成Java的Array  * @author hoojo  * @createDate 2011-4-22 下午12:14:50  */ @Test public void array4Mapping2XML() {     writer = new StringWriter();     Account[] acc = new Account[2];     acc[0] = bean;     bean = new Account();     bean.setName("tom");     bean.setId(223);     acc[1] = bean;     AccountArray array = new AccountArray();     array.setAccounts(acc);     try {         Marshaller mar = new Marshaller(writer);         mar.setMapping(mapping);         mar.marshal(array);         fail(writer);                 reader = new StringReader(writer.toString());         Unmarshaller unmar = new Unmarshaller(AccountArray.class);         unmar.setMapping(mapping);         array = (AccountArray) unmar.unmarshal(reader);         fail(array.getSize());         fail(array.getAccounts()[0]);         fail(array.getAccounts()[1]);     } catch (MarshalException e) {         e.printStackTrace();     } catch (Exception e) {         e.printStackTrace();     } } AccountArray的mapping配置以下: <class name="com.hoo.entity.AccountArray">     <map-to xml="account-array"/>     <field name="size" type="int" />     <field name="accounts" collection="array" type="com.hoo.entity.Account">         <bind-xml name="accounts" auto-naming="deriveByClass"/>     </field> </class> collection表示是數組,auto-maming有2中值,一種是類driverByClass,另外一種則是driverByField是屬性。 運行後,結果以下: <?xml version="1.0" encoding="UTF-8"?> <account-array><size>2</size><Account id="1"><name>jack</name><email>email</email><address>北京</address> <生日 birthday="2010-11-22"/></Account><Account id="223"><name>tom</name></Account></account-array> 2 1#jack#email#北京#2010-11-22 223#tom#null#null#null 四、 將Map編組、解組成JavaObject /**  * <b>function:</b>xml轉換成Java的Map  * @author hoojo  * @createDate 2011-4-22 下午12:15:18  */ @Test public void map4Mapping2XML() {     writer = new StringWriter();     MapBean mapBean = new MapBean();     Map<String, Object> map = new HashMap<String, Object>();     map.put("No1", bean);     bean = new Account();     bean.setName("tom");     bean.setId(223);     map.put("No2", bean);     mapBean.setMap(map);         try {         Marshaller mar = new Marshaller(writer);         mar.setMapping(mapping);         mar.marshal(mapBean);         fail(writer);                 reader = new StringReader(writer.toString());         Unmarshaller unmar = new Unmarshaller(MapBean.class);         unmar.setMapping(mapping);         mapBean = (MapBean) unmar.unmarshal(reader);         fail(mapBean.getMap());     } catch (MarshalException e) {         e.printStackTrace();     } catch (Exception e) {         e.printStackTrace();     } } Mapping配置 <class name="com.hoo.entity.MapBean">     <field name="map" collection="map">         <bind-xml name="map">             <class name="org.exolab.castor.mapping.MapItem">                 <field name="key" type="java.lang.String">                     <bind-xml name="key" node="attribute" />                 </field>                 <field name="value" type="com.hoo.entity.Account">                     <bind-xml name="value" auto-naming="deriveByClass"/>                 </field>             </class>         </bind-xml>     </field> </class> 上面的map配置必須這樣配置,利用org.exolab.castor.mapping.MapItem這個class,完成key、value的配置。 結果以下: <?xml version="1.0" encoding="UTF-8"?> <map-bean><map key="No2"><Account id="223"><name>tom</name></Account></map> <map key="No1"><Account id="1"><name>jack</name><email>email</email><address>北京</address> <生日 birthday="2010-11-22"/></Account></map></map-bean> {No2=223#tom#null#null#null, No1=1#jack#email#北京#2010-11-22} 五、 JavaList編組、解組XML /**  * <b>function:</b>List到XML的相互轉換  * @author hoojo  * @createDate 2011-4-22 下午12:16:04  */ @SuppressWarnings("unchecked") @Test public void listForMapping2XML() {     writer = new StringWriter();         List<Account> list = new ArrayList<Account>();     list.add(bean);     bean = new Account();     bean.setName("tom");     bean.setId(223);     list.add(bean);         ListBean listBean = new ListBean();     listBean.setList(list);     try {         Marshaller mar = new Marshaller(writer);         mar.setMapping(mapping);         mar.marshal(listBean);         fail(writer);                 reader = new StringReader(writer.toString());         Unmarshaller unmar = new Unmarshaller(ListBean.class);         unmar.setMapping(mapping);         listBean = (ListBean) unmar.unmarshal(reader);         fail(listBean.getList().size());         for (Account acc : (List<Account>)listBean.getList()) {             fail(acc);         }     } catch (MarshalException e) {         e.printStackTrace();     } catch (Exception e) {         e.printStackTrace();     } } Mapping配置 <class name="com.hoo.entity.ListBean">     <map-to xml="listBean"/>     <field name="list" collection="arraylist" type="com.hoo.entity.Account">         <bind-xml name="beans" auto-naming="deriveByClass"/>     </field> </class> 結果: <?xml version="1.0" encoding="UTF-8"?> <listBean><Account id="1"><name>jack</name><email>email</email><address>北京</address> <生日 birthday="2010-11-22"/></Account><Account id="223"><name>tom</name></Account></listBean> 2 1#jack#email#北京#2010-11-22 223#tom#null#null#null
相關文章
相關標籤/搜索