Digester : a java object builder based xml

來源:互聯網
上載者:User

標籤:

 

         在Java編程中,設定檔大多數都是用xml檔案來組織的。所以在Java語言中處理xml的工具就特別多。

在java中解析XML的幾種方式,應該都是知道的。在這些解析技術的基礎之上,又發展了幾種優秀Object/XML關聯的技術,例如有一種對象綁定技術(JAXB),再例如Digester。這裡就來簡單的瞭解一下Digester技術。

         如果說對Digester運用最為高超的應用,非Tomcat莫屬了。Tomcat中幾個重要的設定檔(如server.xml、web.xml、context.xml),都是使用Digester來完成xml到Java對象的轉換的。

         Digester只需要設定好相應的處理規定,就可以得到想要的對象結構。它的最大優點就是可以自訂各種處理規則。然而,如果不能明白Digester的設計原理,那你就只使用Digester給你提供的幾種規則了。

 

Digester例子

 

Java對象設計:

package com.fjn.frame.digester.list;public class XxObject {    private String id;    private String name;    private int num;    public String getId() {        return id;    }    public void setId(String id) {        this.id = id;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getNum() {        return num;    }    public void setNum(int num) {        this.num = num;    }    @Override    public String toString() {        return "id: " + id + "\tname: " + name + "\tnum: " + num;    }}

這個類沒有任何的含義,只是我隨便寫的而已。


一個簡單的XML檔案:

<?xml version="1.0" encoding="UTF-8"?><XxObjects>    <XxObject id="id001" name="hello1" num="1" />    <XxObject id="id002" name="hello2" num="2" />    <XxObject id="id003" name="hello3" num="3" />    <XxObject id="id004" name="hello4" num="4" />    <XxObject id="id005" name="hello5" num="5" />    <XxObject id="id006" name="hello6" num="6" />    <XxObject id="id007" name="hello7" num="7" />    <XxObject id="id008" name="hello8" num="8" />    <XxObject id="id009" name="hello9" num="9" /></XxObjects>

 

接下來的任務就是將這個XML檔案轉換為一個對象集合了。 

 

package com.fjn.frame.digester.list;import java.io.IOException;import java.util.List;import javax.xml.parsers.FactoryConfigurationError;import javax.xml.parsers.ParserConfigurationException;import javax.xml.parsers.SAXParser;import javax.xml.parsers.SAXParserFactory;import org.apache.commons.digester3.Digester;import org.junit.Test;import org.xml.sax.SAXException;public class Convertor {    @Test    public void test() throws ParserConfigurationException, SAXException,            FactoryConfigurationError, IOException {        SAXParser parser = SAXParserFactory.newInstance().newSAXParser();        Digester digester = new Digester(parser);        digester.addObjectCreate("XxObjects", "java.util.LinkedList");        digester.addObjectCreate("XxObjects/XxObject",                "com.fjn.frame.digester.list.XxObject");        digester.addSetProperties("XxObjects/XxObject");        // digester.addSetNext("XxObjects/XxObject", "add");        digester.addRule("XxObjects/XxObject", new AddToCollectionRule());        List<XxObject> ret = digester.parse(Convertor.class                .getResourceAsStream("XxObjects.xml"));        for (XxObject obj : ret) {            System.out.println(obj);        }    }}

AddToCollectionRule規則是我自訂的規則: 

package com.fjn.frame.digester.list;import java.util.Collection;import org.apache.commons.digester3.Rule;import org.xml.sax.Attributes;public class AddToCollectionRule extends Rule {    @Override    public void begin(String namespace, String name, Attributes attributes)            throws Exception {        Object top = this.getDigester().peek();        Object o = this.getDigester().peek(1);        if (o != null) {            Collection colls = (Collection) o;            System.out.println(top);            colls.add(top);        }    }}

程式運行結果: 

id: id001name: hello1num: 1id: id002name: hello2num: 2id: id003name: hello3num: 3id: id004name: hello4num: 4id: id005name: hello5num: 5id: id006name: hello6num: 6id: id007name: hello7num: 7id: id008name: hello8num: 8id: id009name: hello9num: 9id: id001name: hello1num: 1id: id002name: hello2num: 2id: id003name: hello3num: 3id: id004name: hello4num: 4id: id005name: hello5num: 5id: id006name: hello6num: 6id: id007name: hello7num: 7id: id008name: hello8num: 8id: id009name: hello9num: 9

使用Digester將xml轉為java對象,就是這麼簡單。 

使用起來如此簡單,它是怎麼做到的呢?

 

 

Digester設計原理

 

  如果是使用DOM解析的方式,我相信只要你瞭解DOM樹,你就肯定能夠完成這個輕鬆的任務,這也是程式員們更加容易接受DOM解析的原因。但是,設想一下,如果讓你來將一個XML檔案使用SAX解析的方式,轉換為Java對象,你會怎麼做呢?

     我在看Digester的源碼之前,就做過這樣的設想。因為SAX解析的方式中,我們使用的最多的應當是startElement和endElement了。SAX解析是基於事件的,遇到一個開始元素,就執行startElement方法,遇到一個結束元素就執行endElement方法。

  一般來說一個XML元素就對應一個Java對象,XML元素的屬性就對應的是Java對象的屬性。遇到一個元素開始,就可以根據元素名稱來建立出對象。根據元素的屬性來設定對象的屬性。這個了是很簡單的,但是在end一個元素後,也就是對象建立完成後,怎麼來儲存呢?總不能解析完成,產生了很多個物件,我一個也拿不到,那解析它有何用呢。可以考慮一個複雜的XML,例如tomcat的server.xml檔案,Server\Service\Engine等有對象是嵌套的,建立一個對象Service後,怎麼將它設定到Server中呢?建立一個對象Engine後,怎麼將它設定到Service中呢。完成這個工作,就必然要使用到一個資料結構:Stack。如果你能想到這裡,Digester你就學會了80%了。

 

Java對象在startElement中建立併入棧,在endElement中完成所有操作並出棧。

 

例子說明

         在上面的例子中,解析到根項目時,會建立出一個LinkedList,然後入棧。因為沒有到結束元素,所以它肯定會在棧裡,並且是在最下面。然後是解析每個XxObject了。在解析XxObject元素時,都要有3個操作,它們是依次進行的:

1)建立XxObject對象。入棧,那麼這個對象肯定是在棧頂了。

2)設定屬性。Digester使用的是BeanUtils工具來完成屬性的設定的,所以java類在設計時, 是需要 getter和setter的。

3)調用我自訂的AddToCollection規則了。執行這個規則也很簡單,取得當前對象(棧頂元素),再取出從棧頂起第二個元素,也就是LinkedList。然後就可以添加到集合中了。

4)endElement,對象出棧,棧中只剩下LinkedList對象。

 最後遇到XxObejcts的end,它就是解析到最後一刻時棧底。返回的什就是棧底對象。所以結果就是一個List了。

 我自訂的那個AddToCollection規則,只是想用於說明如何Digester的原理,以及如何使用自訂規則。其實像這個的常用的規則,Digester已經定義好了,SetNetRule。

 

到這裡,這篇文章的主要內容已經說完了。至於如何使用Digester中的各種Rule,還需要靠自己去瞭解了。

下面附加一張類圖:

 

 

Digester : a java object builder based xml

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.