Digester解析xml文件

 通常用來讀取xml文件的工具包有DOM、SAX和JDOM等,但用過的人都知道,它們屬於比較底層的API,寫起來代碼量很大,並且若是修改了xml文件的格式,代碼也要作大幅度的改動。而使用Apache Jakarta的Digester,解析XML文件很是方便且不須要過多的關心底層的具體解析過程。Digester原本僅僅是Jakarta Struts中的一個工具,用於處理struts-config.xml配置文件。顯然,將XML文件轉換成相應的Java對象是一項很通用的功能,這個工具理應具備更普遍的用途,因此很快它就在Jakarta Commons項目(用於提供可重用的Java組件庫)中有了一席之地。Digester由"事件"驅動,經過調用預約義的規則操做對象棧,將XML文件轉換爲Java對象。html

    工做原理以下: Digester底層採用SAX(Simple API for XML)析XML文件,因此很天然的,對象轉換由"事件"驅動,在遍歷每一個節點時,檢查是否有匹配模式,若是有,則執行規則定義的操做,好比建立特定的Java對象,或調用特定對象的方法等。此處的XML元素根據匹配模式(matching pattern)識別,而相關操做由規則(rule)定義。java

   

1.addObjectCreate(String rule,Class class)web

設置節點與Java對象的映射規則,rule指定節點的篩選規則,class設置映射對象。SAX解析時,遇到rule指定的節節點,會建立一個class實例放入堆棧中。apache

好比:digester.addObectCreate("database/user","com.model.UserBean").解析遇到user節點時,會建立一個UserBean實例並放入堆棧中。api

2.addSetProperties(String rule)工具

設置節點的屬性設置規則。當解析遇到符合rule的節點時,根據屬性列表中的屬性值對,使用Java反射機制使用標準的JavaBean方法設置棧頂對象實例;this

好比:digester.addSetProperties("database/user"),解析遇到user節點時,會獲取鍵值對 userName=guest,password=guest,得到棧頂的UserBean對象,設置實例的userName、password屬性;編碼

3.addBeanPropertySetter(String rule)spa

該方法的做用及使用方法相似於addSetProperties,只不過它是用rule所指定的標籤來調用對象的setter。.net

4.addSetNext(String rule,String methodName)

設置當前rule節點與父節點的調用規則,當遇到rule節點時,調用堆棧中的次棧頂元素調用methodName方法。將棧頂元素做爲次頂元素指定方法的輸入參數。

好比:digester.addSetNext("database/user","addUser"),調用database實例的addUser,user爲參數

5.addCallMethod(String rule,String methodName,int paraNumber)

該方法一樣設置對象的屬性,但更加靈活,不須要對象具備setter

根據rule規則指定的屬性,調用對象的methodName方法,paraNumber參數是表示方法須要的參數個數,當paraNumber=0時,能夠單獨使用,否則須要配合addCallParam方法

好比:digester.addCallMethod("database/user/userName","setUserName",0), 參數爲xml當前值;無參方法:digester.addCallMethod( "pattern", "methodName" );.

6.addCallParam(String rule,int paraIndex,String attributeName)

該方法與addCallMethod配合使用,根據rule指定的標籤屬性來調用方法

paraIndex代表須要填充的方法形參序號,從0開始,方法由addCallMethdo指定,attributeName指定標籤屬性名;

使用注意事項:
   1.Digester類調用的順序,必須與XML數據文件絕對一致;
   2.Digester類依賴於JavaBean規範,類必須符合規範;
   3.XML文件中標籤/屬性的名稱必須與Bean中的一致(包括大小寫);

//--webconfig.xml--
<?xml version="1.0" encoding="UTF-8"?>
<web>
<root name = "root_name1">
<bar id="0" title="The Zero Child"/>
<bar id="123" title="The First Child"/>
<bar id="456" title="The Second Child"/>
</root>
<root name = "root_name2">
<bar id="789" title="Another Child"/>
</root>
</web>

Digest  
Digester digester = new Digester(); 新建一個類
digester.setValidating(false); 是否進行XML與相應的DTD的合法性驗證(此處爲false)
digester.addObjectCreate("root", "Root"); 當遇到<root>時建立一個Root對象,並將其放在棧頂
digester.addSetProperties("root"); 根據<root>元素的屬性(attribute),對剛建立的Root對象的屬性(property)進行設置
digester.addObjectCreate("root/bar", "Bar"); 當遇到<root>的子元素<bar>時建立一個Bar對象,並將其放在棧頂。
digester.addSetProperties("root/bar"); 根據<bar>元素的屬性(attribute),對剛建立的Bar對象的屬性(property)進行設置
digester.addSetNext("root/bar", "addBar", "Bar"); 當再次遇到<root>的子元素<bar>時建立一個Bar對象,並將其放在棧頂,同時調用第二棧頂元素(Root對象)的addBar方法。
digester.parse();

進行解析,獲得的是Object

 

 以下xml代碼,右邊是左邊元素對應的匹配模式:

 

[xhtml]  view plain  copy
 
  1. <datasources>          'datasources'   
  2.   <datasource>         'datasources/datasource'   
  3.     <name/>            'datasources/datasource/name'   
  4.     <driver/>          'datasources/datasource/driver'    
  5.   </datasource>   
  6.   <datasource>         'datasources/datasource'   
  7.     <name/>            'datasources/datasource/name'   
  8.     <driver/>          'datasources/datasource/driver'    
  9.   </datasource>   
  10. </datasources>   

 

 

例子1:

下面介紹解析xml文件的代碼

 

下面是存放地址及編碼的xml文件viewcache.xml(片斷):

 

[xhtml] view plain copy
 
  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2. <viewcache>  
  3.     <areas>  
  4.         <area>  
  5.             <id>1098</id>  
  6.             <parentId>1001</parentId>  
  7.             <areaType>province</areaType>  
  8.             <name>北京</name>  
  9.             <ordering>1867</ordering>  
  10.         </area>  
  11.         <area>  
  12.             <id>1099</id>  
  13.             <parentId>1098</parentId>  
  14.             <areaType>capital</areaType>  
  15.             <name>北京</name>  
  16.             <ordering>1868</ordering>  
  17.             <phoneArea>010</phoneArea>  
  18.         </area>  
  19.         <area>  
  20.             <id>4476</id>  
  21.             <parentId>1099</parentId>  
  22.             <areaType>county</areaType>   
  23.             <name>北京市朝陽區</name>  
  24.             <ordering>1869</ordering>  
  25.             <phoneArea>010</phoneArea>  
  26.         </area>  
  27.         <area>  
  28.             <id>4477</id>  
  29.             <parentId>1099</parentId>  
  30.             <areaType>county</areaType>  
  31.             <name>北京市崇文區</name>  
  32.             <ordering>1870</ordering>  
  33.             <phoneArea>010</phoneArea>  
  34.         </area>  
  35.         <area>  
  36.             <id>4478</id>  
  37.             <parentId>1099</parentId>  
  38.             <areaType>county</areaType>  
  39.             <name>北京市大興區</name>  
  40.             <ordering>1871</ordering>  
  41.             <phoneArea>010</phoneArea>  
  42.         </area>  
  43.     </areas>  
  44. </viewcache>  

 

此xml文件分3層結構,分別爲:

<viewcache>節點 其下包含1個<areas>節點

<areas>節點 其下包含多個<area>節點

<area>節點,其下包含各類信息節點 : 如:<id> 、<name>等。 

咱們的操做目標是把area中的信息節點的內容提取出來。 
把每一個<arrea>看作爲一個對象,<area>中信息節點的內容爲對象中的元素。 
設定一個類Area.java 其內容以下: 

 

[java]  view plain  copy
 
  1. public class Area {  
  2.     private int    id;  
  3.     private String name;  
  4.     private String areaType;  
  5.     private int    parentId;  
  6.     private int    ordering;  
  7.     private String zip;  
  8.       
  9.     private String phoneArea;  
  10.       
  11.     public int getOrdering() {  
  12.         return ordering;  
  13.     }  
  14.     public void setOrdering(int ordering) {  
  15.         this.ordering = ordering;  
  16.     }  
  17.     public String getAreaType() {  
  18.         return areaType;  
  19.     }  
  20.     public void setAreaType(String areaType) {  
  21.         this.areaType = areaType;  
  22.     }  
  23.     public int getId() {  
  24.         return id;  
  25.     }  
  26.     public void setId(int id) {  
  27.         this.id = id;  
  28.     }  
  29.     public String getName() {  
  30.         return name;  
  31.     }  
  32.     public void setName(String name) {  
  33.         this.name = name;  
  34.     }  
  35.     public int getParentId() {  
  36.         return parentId;  
  37.     }  
  38.     public void setParentId(int parentId) {  
  39.         this.parentId = parentId;  
  40.     }  
  41.       
  42.     public String getZip() {  
  43.         return zip;  
  44.     }  
  45.       
  46.     public void setZip(String zip) {  
  47.         this.zip = zip;  
  48.     }  
  49.       
  50.     public String getPhoneArea() {  
  51.         return phoneArea;  
  52.     }  
  53.       
  54.     public void setPhoneArea(String phoneArea) {  
  55.         this.phoneArea = phoneArea;  
  56.     }  
  57. }  

 

 

建立一個ViewCache類,用來保存解析後的全部對象:

 

[java]  view plain  copy
 
  1. public class ViewCache {  
  2.     private List areaList             = new ArrayList();  
  3.     public List getAreaList() {  
  4.         return areaList;  
  5.     }  
  6.     public void setAreaList(List areaList) {  
  7.         this.areaList = areaList;  
  8.     }  
  9.       
  10.     // 供Digester調用的方法  
  11.     public void addArea(Area area) {  
  12.         this.areaList.add(area);  
  13.     }  
  14. }  

 

 

建立一個類AreaDigester,對xml文件進行解析:

 

[java] view plain copy
 
  1. public class AreaDigester {  
  2.       
  3.     public ViewCache digester() throws Exception {  
  4.         Digester digester = new Digester();  
  5.         digester.setValidating(false);  
  6.   //addObjectCreate:當碰到第一個參數的節點時建立類型爲第二個參數的對象並壓入棧中
  7.         digester.addObjectCreate("viewcache/areas", ViewCache.class);  
  8.         // 指明匹配模式和要建立的類   
  9.         digester.addObjectCreate("viewcache/areas/area", Area.class);  
  10.         // 設置對象屬性,與xml文件對應,不設置則是默認  
  11.   ////addBeanPropertySetter:當碰到第一個參數的節點時執行棧頂對象的第二個參數的setter方法,參數爲該節點的內容
  12.         digester.addBeanPropertySetter("viewcache/areas/area/id", "id");  
  13.         digester.addBeanPropertySetter("viewcache/areas/area/parentId", "parentId");  
  14.         digester.addBeanPropertySetter("viewcache/areas/area/name", "name");  
  15.         digester.addBeanPropertySetter("viewcache/areas/area/areaType", "areaType");  
  16.         digester.addBeanPropertySetter("viewcache/areas/area/ordering", "ordering");  
  17.         digester.addBeanPropertySetter("viewcache/areas/area/zip", "zip");  
  18.         digester.addBeanPropertySetter("viewcache/areas/area/phoneArea", "phoneArea");  
  19.         // 當移動到下一個標籤中時的動做  
  20.   ////當碰到第一個參數節點的結束標誌時彈出棧頂元素,執行新棧頂元素的第二個參數的方法,並將彈出的棧頂元素看成該方法的參數
  21.         digester.addSetNext("viewcache/areas/area", "addArea");  
  22.           
  23.         ViewCache vc = null;  
  24.         try {  
  25.             vc = (ViewCache) digester.parse("viewcache.xml");  
  26.         } catch (IOException e) {  
  27.             throw new Exception(e);  
  28.         } catch (SAXException e) {  
  29.             throw new Exception(e);  
  30.         }  
  31.         return vc;  
  32.     }  
  33. }  

 

調用AreaDigester的digester方法,便可把解析後的全部地址對象,存放在ViewCache的list中。

 

例子2:

要解析的xml文件books.xml以下:

 

[xhtml]  view plain  copy
 
  1. <?xml version="1.0" encoding="UTF-8" ?>   
  2. <library name="alibaba圖書館">   
  3.      <book title ="thinking in java"  author="xxx">   
  4.          <chapter>   
  5.              <no>第一章</no>   
  6.              <caption>第一章的標題</caption>   
  7.          </chapter>   
  8.          <chapter>   
  9.              <no>第二章</no>   
  10.              <caption>第二章的標題</caption>   
  11.          </chapter>   
  12.      </book>   
  13.      <book title="effective java"  author="yyy">   
  14.          <chapter>   
  15.              <no>第一章</no>   
  16.              <caption>第一章的標題</caption>   
  17.          </chapter>   
  18.      </book>   
  19. </library>  

 

Library類以下:

 

[java]  view plain  copy
 
  1. public class Library {  
  2.     private String name;  
  3.     private List<Book> bookList = new ArrayList<Book>();  
  4.       
  5.     public String getName() {  
  6.         return name;  
  7.     }  
  8.       
  9.     public void setName(String name) {  
  10.         this.name = name;  
  11.     }  
  12.       
  13.     public List<Book> getBookList() {  
  14.         return bookList;  
  15.     }  
  16.       
  17.     public void addBook(Book book) {  
  18.         bookList.add(book);  
  19.     }  
  20. }  

 

Book類以下:

 

[java]  view plain  copy
 
  1. public class Book {  
  2.   
  3.     private String        title;  
  4.     private String        author;  
  5.     private List<Chapter> chapters = new ArrayList<Chapter>();  
  6.   
  7.     /** 
  8.      * 這個方法,用來演示xml的解析時用的另外一種方式 
  9.      * @param title 
  10.      * @param author 
  11.      */  
  12.     public void setBookInfo(String title, String author) {  
  13.         this.title = title;  
  14.         this.author = author;  
  15.     }  
  16.   
  17.     public void addChapter(Chapter chapter) {  
  18.         this.chapters.add(chapter);  
  19.     }  
  20.       
  21.     public String getTitle() {  
  22.         return title;  
  23.     }  
  24.       
  25.     public void setTitle(String title) {  
  26.         this.title = title;  
  27.     }  
  28.       
  29.     public String getAuthor() {  
  30.         return author;  
  31.     }  
  32.       
  33.     public void setAuthor(String author) {  
  34.         this.author = author;  
  35.     }  
  36.       
  37.     public List<Chapter> getChapters() {  
  38.         return chapters;  
  39.     }  
  40.   
  41.     public void setChapters(List<Chapter> chapters) {  
  42.         this.chapters = chapters;  
  43.     }  
  44. }  

 

Chapter類以下:

 

[java]  view plain  copy
 
  1. public class Chapter {  
  2.   
  3.     private String no;  
  4.     private String caption;  
  5.   
  6.     public String getNo() {  
  7.         return no;  
  8.     }  
  9.   
  10.     public void setNo(String no) {  
  11.         this.no = no;  
  12.     }  
  13.   
  14.     public String getCaption() {  
  15.         return caption;  
  16.     }  
  17.   
  18.     public void setCaption(String caption) {  
  19.         this.caption = caption;  
  20.     }  
  21. }  

 

解析xml的類以下:

 

[java]  view plain  copy
 
  1. public class MainTest {  
  2.   
  3.     /** 
  4.      * @param args 
  5.      */  
  6.     public static void main(String[] args) {  
  7.         // 創建一個Digester對象  
  8.         Digester digester = new Digester();  
  9.         //指定它不要用DTD驗證XML文檔的合法性——這是由於咱們沒有爲XML文檔定義DTD  
  10.         digester.setValidating(false);  
  11.         // 從library標籤開始解析,並新建一個Library對象作爲根對象  
  12.         digester.addObjectCreate("library", Library.class);  
  13.         // 根據library標籤屬性值設置對象的屬性,一次能夠設置多個屬性  
  14.         digester.addSetProperties("library");  
  15.         // 也能夠用下面的方法,指定propertyName  
  16.         // digester.addSetProperties("library", "name", "name");  
  17.   
  18.         // -----第1層元素開始  
  19.         digester.addObjectCreate("library/book", Book.class);  
  20.         //digester.addSetProperties("library/book");  
  21.         // 能夠用如下三條語句代替  
  22.         digester.addCallMethod("library/book", "setBookInfo", 2);  
  23.         digester.addCallParam("library/book", 0, "title");  
  24.         digester.addCallParam("library/book", 1, "author");  
  25.         /** 
  26.          * addCallParam(String rule, int  paraIndex,String attributeName) 
  27.          * 該方法與addCallMethod配合使用 
  28.          * int paraIndex:代表須要填充的方法形參序號,從 0 開始,方法由addCallMethod指定 
  29.          * String attributeName:指定標籤屬性名稱 
  30.          */  
  31.           
  32.           
  33.         // -----第2層元素開始  
  34.         digester.addObjectCreate("library/book/chapter", Chapter.class);  
  35.         /** addBeanPropertySetter()是將子節點轉換爲對象的屬性,這個方法還能夠有第二個參數,當對象的屬性名和子節點的名字不同時用來指定對象的屬性名 
  36.             該方法的做用及使用方法相似於addSetProperties,只不過它是用String rule規則所指定標籤的值(而不是標籤的屬性)來調用對象的setter*/  
  37.         digester.addBeanPropertySetter("library/book/chapter/no");  
  38.         // digester.addBeanPropertySetter("library/book/chapter/no", "no");  
  39.           
  40.         /** addCallMethod(String rule,String methodName, int  paraNumber) 方法 
  41.          * 一樣是設置對象的屬性,可是方式更加靈活,不須要對象具備setter 
  42.          * 當paraNumber = 0時,能夠單獨使用(代表爲標籤的值來調用),否則須要配合addCallParam方法 
  43.         */  
  44.         // digester.addBeanPropertySetter("library/book/chapter/caption");  
  45.         // 下面的方法,能夠用來代替上一句,做用是同樣的   
  46.         digester.addCallMethod("library/book/chapter/caption", "setCaption", 0);  
  47.   
  48.         // addSetNext()是說在再次遇到匹配節點後, 調用當前對象(Chapter類的對象)的父對象(Book類的對象)的方法,方法參數是當前層元素的對象  
  49.         digester.addSetNext("library/book/chapter", "addChapter");  
  50.         // -----第2層元素結束  
  51.   
  52.         digester.addSetNext("library/book", "addBook");  
  53.         // -----第1層元素結束  
  54.   
  55.         try {  
  56.             // 解析XML文件,並獲得ROOT元素  
  57.             Library library = (Library) digester.parse(MainTest.class.getResourceAsStream("books.xml"));  
  58.             System.out.println(" 圖書館: " + library.getName());  
  59.             System.out.println(" 共藏書: " + library.getBookList().size() + " 本 ");  
  60.             System.out.println(" ***************************** ");  
  61.   
  62.             for (Book book : library.getBookList()) {  
  63.                 System.out.println(" 書名: " + book.getTitle() + "        做者: " + book.getAuthor());  
  64.                 System.out.println(" ------------------------------ ");  
  65.                 // 顯示章節  
  66.                 System.out.println(" 共 " + book.getChapters().size() + " 章 ");  
  67.                 for (Chapter chapter : book.getChapters()) {  
  68.                     System.out.println(chapter.getNo() + ": " + chapter.getCaption());  
  69.                 }  
  70.                 System.out.println(" ------------------------------ ");  
  71.             }  
  72.         } catch (IOException e) {  
  73.             e.printStackTrace();  
  74.         } catch (SAXException e) {  
  75.             e.printStackTrace();  
  76.         }  
  77.     }  
  78. }  

 

 

 

例子3:

 

Digester解析xml的規則,除了在java類中描述設置以外,還能夠把解析規則放在xml文件中。以例子2中的代碼爲例,規則在books-rule.xml文件中,內容以下:(The DTD is distributed in the commons-digester.jar. It can be found at org/apache/commons/digester/xmlrules/digester-rules.dtd,經過查看DTD文件,能夠知道有哪些標籤可使用)

 

[xhtml]  view plain  copy
 
  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2. <!DOCTYPE digester-rules PUBLIC  
  3.    "-//Jakarta Apache //DTD digester-rules XML V1.0//EN"  
  4.    "digester-rules.dtd">   
  5. <digester-rules>    
  6.     <object-create-rule pattern="library" classname="com.alibaba.chj.digester.Library" />    
  7.     <set-properties-rule pattern="library">    
  8.         <alias attr-name="name" prop-name="name" />    
  9.     </set-properties-rule>    
  10.     <pattern value="library/book">    
  11.         <object-create-rule classname="com.alibaba.chj.digester.Book" />    
  12.         <set-properties-rule />    
  13.         <pattern value="chapter">    
  14.             <object-create-rule classname="com.alibaba.chj.digester.Chapter" />    
  15.             <bean-property-setter-rule pattern="no" propertyname="no" />  
  16.             <bean-property-setter-rule pattern="caption" propertyname="caption" />  
  17.             <set-next-rule methodname="addChapter" />    
  18.         </pattern>       
  19.         <set-next-rule methodname="addBook" />    
  20.     </pattern>    
  21. </digester-rules>    

 

 

解析xml類的代碼,修改成:

 

[java]  view plain  copy
 
  1. public class MainTest {  
  2.   
  3.     /** 
  4.      * @param args 
  5.      */  
  6.     public static void main(String[] args) {  
  7.         try {      
  8.             Digester digester = DigesterLoader.createDigester(DigesterXmlRuleTest.class.getResource("books-rule.xml"));      
  9.             Library library = (Library) digester.parse(DigesterXmlRuleTest.class.getResourceAsStream("books.xml"));      
  10.             System.out.println(" 圖書館: " + library.getName());  
  11.             System.out.println(" 共藏書: " + library.getBookList().size() + " 本 ");  
  12.             System.out.println(" ***************************** ");  
  13.   
  14.             for (Book book : library.getBookList()) {  
  15.                 System.out.println(" 書名: " + book.getTitle() + "        做者: " + book.getAuthor());  
  16.                 System.out.println(" ------------------------------ ");  
  17.                 // 顯示章節  
  18.                 System.out.println(" 共 " + book.getChapters().size() + " 章 ");  
  19.                 for (Chapter chapter : book.getChapters()) {  
  20.                     System.out.println(chapter.getNo() + ": " + chapter.getCaption());  
  21.                 }  
  22.                 System.out.println(" ------------------------------ ");  
  23.             }     
  24.         } catch (IOException e) {  
  25.             e.printStackTrace();  
  26.         } catch (SAXException e) {  
  27.             e.printStackTrace();  
  28.         }   
  29.     }  
  30. }  

 

用於規則放在xml文件中,因此解析的類,顯得更加簡潔一些。

相關文章
相關標籤/搜索