隨筆 - 20  文章 - 12  trackbacks - 0
          <2006年3月>
          2627281234
          567891011
          12131415161718
          19202122232425
          2627282930311
          2345678

          常用鏈接

          留言簿(1)

          隨筆檔案(20)

          java論壇

          我的朋友

          最新隨筆

          搜索

          •  

          積分與排名

          • 積分 - 15158
          • 排名 - 1997

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          Digester學(xué)習(xí)筆記(一)

            在windows下開發(fā)程序,用M$提供的接口處理.ini文件或管理注冊(cè)表的鍵值是非常方便的。在java平臺(tái)上開發(fā)程序,則習(xí)慣于以xml 格式的文件來存放系統(tǒng)的配置信息,對(duì)這種文件的解析和處理,可以用sax或dom。有沒有更簡(jiǎn)便的方法呢?有,就是用digester模塊。
            Digester是Jakarta 子項(xiàng)目Commons下的一個(gè)模塊,支持基于規(guī)則的對(duì)任意XML文檔的處理。它最初是Structs項(xiàng)目的一部分,后因其通用性而劃歸Commons.

          下載及編譯

          cvs -d :pserver:anoncvs@cvs.apache.org:/home/cvspublic login
          password: anoncvs
          cvs -d :pserver:anoncvs@cvs.apache.org:/home/cvspublic checkout jakarta-commons/digester
          cd jakarta-commons/digester
          ant dist

            Digester的運(yùn)行依賴下列包:
          1. 一個(gè)遵循Jaxp(1.1版本及以后)的XML解析器
          2. Jakarta commons beanutils包(1.5版本及以后)
          3. Jakarta commons collections包(2.1版本及以后)
          4. Jakarta commons logging包(1.0.2版本及以后)
           

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

            假定有兩個(gè)JavaBean如下,分別為Foo和Bar
          package mypackage;
          public class Foo {
          ??public void addBar(Bar bar);
          ??public Bar findBar(int id);
          ??public Iterator getBars();
          ??public String getName();
          ??public void setName(String name);
          }
          public mypackage;
          public class Bar {
          ??public int getId();
          ??public void setId(int id);
          ??public String getTitle();
          ??public void setTitle(String title);
          }

            用下面的xml文件進(jìn)行配置
          <foo name="The Parent">
          ??<bar id="123" title="The First Child"/>
          ??<bar id="456" title="The Second Child"/>
          </foo>

            用下面幾行代碼即可完成配置文件解析工作:
          Digest解析代碼注釋
          Digesterdigester = new Digester();
          digester.setValidating(false);不進(jìn)行XML與相應(yīng)的DTD的合法性驗(yàn)證
          digester.addObjectCreate("foo", "mypackage.Foo");當(dāng)遇到<foo>時(shí)創(chuàng)建一個(gè)mypackage.Foo對(duì)象,并將其放在棧頂
          digester.addSetProperties("foo");根據(jù)<foo>元素的屬性(attribute),對(duì)剛創(chuàng)建的Foo對(duì)象的屬性(property)進(jìn)行設(shè)置
          digester.addObjectCreate("foo/bar", "mypackage.Bar");當(dāng)遇到<foo>的子元素<bar> 時(shí)創(chuàng)建一個(gè)mypackage.Bar對(duì)象,并將其放在棧頂。
          digester.addSetProperties("foo/bar");根據(jù)<bar>元素的屬性(attribute),對(duì)剛創(chuàng)建的Bar對(duì)象的屬性(property)進(jìn)行設(shè)置
          digester.addSetNext("foo/bar", "addBar", "mypackage.Bar ");當(dāng)再次遇到<foo>的子元素<bar>時(shí)創(chuàng)建一個(gè)mypackage.Bar對(duì)象,并將其放在棧頂,同時(shí)調(diào)用第二棧頂元素(Foo對(duì)象)的addBar方法。
          Foo foo = (Foo) digester.parse();分析結(jié)束后,返回根元素。

          基本情況

            熟悉用SAX來處理XML文檔的程序員,會(huì)發(fā)現(xiàn)Digester隱藏了遍歷XML元素這些細(xì)節(jié),而是提供了更高一層的、更友好的SAX事件接口,從而讓程序員的精力放在對(duì)數(shù)據(jù)的處理過程中。
            使用Digester,須按照以下步驟:
          1. 創(chuàng)建一個(gè)org.apache.commons.digester.Digester實(shí)例。一個(gè)解析請(qǐng)求完成后,這個(gè)Digester可以被后面復(fù)用。但也不要試圖在不同的線程中從共享一個(gè) Digester實(shí)例。
          2. 根據(jù)需要設(shè)置一些配置屬性(configuration properties),以控制下一步的解析操作。
          3. 將一個(gè)或幾個(gè)初始對(duì)象(initial object)壓入Digester對(duì)象棧,本步驟不是必須的。
          4. 注冊(cè)所有的元素匹配模板(elemet matching pattern)。當(dāng)一個(gè)模板被從輸入文檔中識(shí)別出來以后,與其相聯(lián)系的處理規(guī)則(processing rules)被激活。對(duì)一個(gè)特定的模板,可以定義任意多的規(guī)則,當(dāng)識(shí)別出該模板后,這些規(guī)則依序依次執(zhí)行。
          5. 調(diào)用digester.parse()方法,一個(gè)XML文檔的引用(用多種方式供選擇)要傳給這個(gè)方法。注意,需要捕捉并處理IOException或SAXEception或處理過程中拋出的異常。

          元素匹配模板

            Digester能自動(dòng)遍歷目標(biāo)XML文檔的元素形成的層次結(jié)構(gòu),這個(gè)過程無需程序員參與。程序員的任務(wù)是決定,在解析的過程中,當(dāng)由嵌套的元素形成的一個(gè)特定序列被識(shí)別出時(shí),如何處理它。用以描述這種序列的機(jī)制,就叫"元素匹配模板"。
            具體說來,元素和其子元素間,用"/"相隔,如果一些元素前沒有"/"則其必為根元素。如例:
          <a>?????????--?匹配模板?"a"
          ??<b>???????--?匹配模板?"a/b"
          ????<c/>????--?匹配模板?"a/b/c"
          ????<c/>????--?匹配模板?"a/b/c"
          ??</b>
          ??<b>???????--?匹配模板?"a/b"
          ????<c/>????--?匹配模板?"a/b/c"
          ????<c/>????--?匹配模板?"a/b/c"
          ????<c/>????--?匹配模板?"a/b/c"
          ??</b>
          </a>

            字符"*"表示任意級(jí)別,如"*/a"表示任意級(jí)別的<a>都可匹配(不包括根元素級(jí)的).熟悉XLST的朋友,對(duì)這種思路一定不陌生。
            從上面的描述,可知某個(gè)元素同時(shí)滿足多個(gè)匹配模板是非??赡艿?wbr>,在這種情況下,與各個(gè)模板相關(guān)聯(lián)的處理規(guī)則(processing rule)的執(zhí)行順序如下:對(duì)begin或body方法,按照各個(gè)rule的注冊(cè)順序的先后,對(duì)end方法則是注冊(cè)順序的反序。

          處理規(guī)則(processing rule)

            元素匹配模板用以識(shí)別什么時(shí)候采取行動(dòng),處理規(guī)則則用以定義行動(dòng)的內(nèi)容。
            從形式上講,一個(gè)處理規(guī)則是一個(gè)java類,它擴(kuò)展了org.apache.commons.digester.Rule類。每個(gè)處理規(guī)則,實(shí)現(xiàn)下列的一個(gè)或幾個(gè)事件處理方法(event method),當(dāng)相應(yīng)的模板匹配成功以后,在已定義的某個(gè)時(shí)刻,這些事件方法會(huì)被觸發(fā)。
          1. begin(),在一個(gè)匹配元素被識(shí)別出后的"開始"時(shí)刻被調(diào)用,這個(gè)元素的所有屬性放在一個(gè)數(shù)據(jù)結(jié)構(gòu)中被傳遞給begin()
          2. body(),當(dāng)元素的嵌套內(nèi)容(如子元素)被識(shí)別出時(shí)被調(diào)用。在解析的過程中,前后的空白被去掉了
          3. end(),匹配元素的"結(jié)束"時(shí)刻被調(diào)用。如果子元素也匹配相關(guān)的規(guī)則,則這些規(guī)則的方法需都執(zhí)行畢,才能達(dá)到該元素的"結(jié)束"時(shí)刻。
          4. finish(),解析結(jié)束時(shí)被調(diào)用,以提供給各個(gè)規(guī)則以清理臨時(shí)數(shù)據(jù)的機(jī)會(huì)。

            在設(shè)置digester時(shí),通過調(diào)用addRule()方法,來注冊(cè)一個(gè)特定的元素匹配模板以及相應(yīng)的一個(gè)Rule類的實(shí)例。如上所述,Rule類中的事件處理方法,會(huì)在適當(dāng)?shù)臅r(shí)間被調(diào)用。這個(gè)機(jī)制,允許動(dòng)態(tài)地生成Rule的實(shí)現(xiàn)。
            另外,digester也提供了一些處理常見情況的處理規(guī)則類。
          1. ObjectCreateRule,當(dāng)begin()方法被調(diào)用時(shí),這個(gè)規(guī)則類實(shí)例化一個(gè)指定的java類,并將其壓入棧頂。這個(gè)被實(shí)例化的類的名字,默認(rèn)是這個(gè)規(guī)則類構(gòu)造函數(shù)得到的參數(shù),也可以通過指定正在處理的xml元素的屬性來傳遞一個(gè)新的類的名字。當(dāng)end()方法被調(diào)用 時(shí),棧頂?shù)膶?duì)象被彈出,Digester中對(duì)它的任何引用將被忽略。
          2. FactoryCreateRule,一個(gè)非常有用的ObjectCreateRule的變體。
          3. SetPropertiesRule,當(dāng)begin()方法被調(diào)用時(shí),digester 使用標(biāo)準(zhǔn)的Java Relection API來識(shí)別JavaBean的屬性設(shè)置方法(setter method),這些方法名稱中包含屬性(property)的名字,這些屬性與XML元素的屬性(attribute)匹配,于是這些方法被調(diào)用并將相應(yīng)的屬性值(attribute value)傳給它們。這些自然的映射可以被重寫。建議不要過度使用這項(xiàng)功能,在大多數(shù)情況下,使用標(biāo)準(zhǔn)的BeanInfo機(jī)制會(huì)更好。
          4. SetPropertyRule,當(dāng)begin()方法被調(diào)用時(shí),digester調(diào)用棧頂對(duì)象的一個(gè)特定的屬性設(shè)置方法(property setter)并傳給它特定的值(property和值分別由兩個(gè) attribute命名)。這對(duì)XML需要遵循一個(gè)指定的DTD時(shí)比較有用,你可以設(shè)置一個(gè)特別的屬性(property),雖然在指定DTD沒有attribute與其相對(duì)應(yīng)。
          5. SetNextRule,當(dāng)end()方法被調(diào)用時(shí),digester分析第二棧頂元素,尋找一個(gè)特定屬性(property)的設(shè)置方法 (setter method),并接著調(diào)用這個(gè)方法,以棧頂?shù)脑刈鲄?shù)。這個(gè)規(guī)則通常用來在兩個(gè)對(duì)象間建立1對(duì)多的關(guān)系,所用的方法也常被叫做addChild什么的。
          6. SetTopRule,當(dāng)end()方法被調(diào)用時(shí),digester分析棧頂元素,尋找一個(gè)特定屬性(property)的設(shè)置方法 (setter method),并接著調(diào)用這個(gè)方法,以第二棧頂?shù)脑刈鲄?shù)。這個(gè)規(guī)則通常用來在兩個(gè)對(duì)象間建立1對(duì)多的關(guān)系,所用的方法也常被叫做setParent 什么的。
          7. CallMethodRule,這個(gè)規(guī)則設(shè)置當(dāng)end()被調(diào)用時(shí)執(zhí)行的棧頂對(duì)象的自定義方法,通過對(duì)這個(gè)規(guī)則的設(shè)置,來指定方法的名字、參數(shù)的數(shù)量以及定義的參數(shù)類型的Java類的名字。實(shí)際的參數(shù)值,來自激活這個(gè)方法的元素的子元素。
          8. CallParamRule,這個(gè)規(guī)則用來指定CallMethodRule的參數(shù)的值的來源,它可以來自一個(gè)特定的屬性,或子元素的body的內(nèi)容.
          9. NodeCreateRule,一個(gè)特殊的規(guī)則,將對(duì)象樹的一部分轉(zhuǎn)換成一個(gè)DOM結(jié)點(diǎn)(Node),并壓入棧頂。

            對(duì)這些標(biāo)準(zhǔn)的規(guī)則類,可以創(chuàng)建它們的實(shí)例,并調(diào)用digester.addRule來注冊(cè)它們。由于經(jīng)常使用它們,所以digester定義了一些簡(jiǎn)便的方法來注冊(cè)它們。如:
          Rule rule = new SetNextRule(digester, "addChild","com.mycompany.mypackage.MyChildClass");
          digester.addRule("a/b/c", rule);
          可以用下列代碼替換
          digester.addSetNext("a/b/c", "addChild", "com.mycompany.mypackage.MyChildClass");

          Digester學(xué)習(xí)筆記(二)

            為便于理解,將筆記的內(nèi)容結(jié)構(gòu)作了一些調(diào)整。

          對(duì)象棧

            對(duì)digester技術(shù)最普通的應(yīng)用,是用來動(dòng)態(tài)創(chuàng)建一個(gè)由Java對(duì)象構(gòu)成的樹結(jié)構(gòu),各對(duì)象的屬性以及對(duì)象間的關(guān)系,基于XML文檔的內(nèi)容來設(shè)置(XML文檔就是一棵樹)。為實(shí)現(xiàn)這種應(yīng)用,Digester提供了一個(gè)對(duì)象棧,以供在相關(guān)的模板識(shí)別后被激活的處理規(guī)則操作。此棧的基本操作包括:
          1. clear(),清空棧的內(nèi)容
          2. peek(),返回對(duì)棧頂對(duì)象的引用
          3. pop(),將棧頂對(duì)象彈出并返回
          4. push(),將一個(gè)新的對(duì)象壓入棧頂

            用棧的原因,就是當(dāng)識(shí)別出一個(gè)XML元素的"開始"時(shí),將相關(guān)對(duì)象生成并壓入棧頂,這個(gè)對(duì)象在處理該元素的子元素的過程中一直在棧中,當(dāng)所有子元素都處理完后,解析器遇到這個(gè)元素的"結(jié)束"時(shí),則彈出此對(duì)象,并進(jìn)行相關(guān)的處理。
            如何描述對(duì)象間的關(guān)系呢?將棧頂?shù)膶?duì)象做為一個(gè)參數(shù),傳遞給第二棧頂(即先于棧頂對(duì)象入棧的那個(gè)對(duì)象,在棧頂對(duì)象的下面)的一個(gè)方法,就可以簡(jiǎn)單地建立起一種"父子關(guān)系",從而可以簡(jiǎn)單地建立起1:1的關(guān)系(第二棧頂對(duì)象與棧頂對(duì)象之間)和1:N的關(guān)系(第二棧頂對(duì)象不動(dòng),N次壓棧頂彈棧頂對(duì)象).
            如果取得生成的第一個(gè)對(duì)象呢?可以讓parse()方法返回,或者在調(diào)用parse()方法前,先行壓入一個(gè)對(duì)象,在parse()方法結(jié)束后彈出這個(gè)對(duì)象,則其子對(duì)象即為我們想要的第一個(gè)對(duì)象。

          日志(logging)


            日志是一個(gè)調(diào)試Digester規(guī)則集的非常重要的工具,它可以記錄非常豐富的信息,因它在使用Digester之前有必要了解日志是如何工作的。
            Digester使用Jakarta Commons Logging,這個(gè)模塊并不是具體的日志實(shí)現(xiàn),而只是一個(gè)可設(shè)置的接口??梢栽O(shè)置它將各種日志信息傳遞它自身帶的基本記錄器,或者傳遞給其它的更復(fù)雜的日志工具。具體請(qǐng)參考commons logging的文檔,或Jakarta Commons Logging學(xué)習(xí)筆記
            Digester主要使用兩個(gè)記錄器:
          1. SAX相關(guān)的信息,被送往org.apache.commons.digester.Digester.sax記錄器,記錄了Digester收到的SAX的事件的信息。
          2. 其它的所有信息,都被送往org.apache.commons. digester.Digester記錄器,這個(gè)記錄器在調(diào)試Digester時(shí)打開而在產(chǎn)品中常將其關(guān)閉

            假定用commons logging自帶的基本日志工具,并以DEBUG級(jí)別記錄Digester調(diào)試信息以及INFO級(jí)別記錄SAX事件信息,則對(duì)logging的配置文件設(shè)置如下:
          org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog org.apache.commons.logging.simplelog.log.org.apache.commons.digester.Digester=debug org.apache.commons.logging.simplelog.log.org.apache.commons.digester.Digester.sax=info

          Digester包中的例子

          ***********Example.xml**********
          <address-book>
          ??<person?id="1"?category="acquaintance"?try="would?be?ignored">
          ????<name>Gonzo</name>
          ????<email?type="business"> gonzo@muppets.com</email>
          ????<gender?result="the?whole?tag?would?be?ignored">male</gender>
          ??</person>
          ??<person?id="2"?category="rolemodel">
          ????<name>Kermit</name>
          ????<email?type="business">kermit@muppets.com</email>
          ????<email?type="home">kermie@acme.com</email>
          ??</person>
          </address-book>**********Person.java************
          import?java.util.HashMap;
          import?java.util.Iterator;
          public?class?Person?{
          ??private?int?id;
          ??private?String?category;
          ??private?String?name;
          ??private?HashMap?emails?=?new?HashMap();
          ??//下面的兩個(gè)方法的名字中set以后的部分,與<person>的屬性名字對(duì)映。當(dāng)從xml文件中識(shí)別出<person> 的屬性時(shí),如果有要求(即調(diào)用過addSetProperties方法),Digester會(huì)依據(jù)這種對(duì)映關(guān)系自動(dòng)調(diào)用相應(yīng)的方法。
          ??public?void?setId(int?id)?{
          ??????this.id?=?id;
          ??}
          ??public?void?setCategory(String?category)?{
          ??????this.category?=?category;
          ??}
          ? ?//對(duì)name而言,因?yàn)槠渲祦碜?lt;name>標(biāo)簽的內(nèi)容而非屬性值,需要用addCallMethod指定識(shí)別< name>后的要調(diào)用此方法(想自動(dòng)調(diào)用也要可以,需要addBeanPropertySetter,參見第下一個(gè)例子)。
          ??public?void?setName(String?name)?{
          ??????this.name?=?name;
          ??}
          ??//同name,此時(shí)還要一一指定addEmail的參數(shù)值的來源。
          ??public?void?addEmail(String?type,?String?address)?{
          ??????emails.put(type,?address);
          ??}
          ??public?void?print()?{
          ??????System.out.println("Person?#"?+?id);
          ??????System.out.println("??category="?+?category);
          ??????System.out.println ("??name="?+?name);
          ??????for(Iterator?i?=?emails.keySet().iterator();?i.hasNext();?)?{
          ??????????String?type?=?(String)?i.next();
          ??????????String?address?=?(String)?emails.get(type);
          ??????????System.out.println("??email?(type?"?+?type?+?")?:?"?+?address);
          ??????}
          ??}
          }
          **********AddressBook.java***********
          import?java.util.LinkedList;
          import?java.util.Iterator;
          public?class?AddressBook?{
          ????LinkedList?people?=?new?LinkedList();
          ????public?void?addPerson(Person?p)?{
          ????????people.addLast(p);
          ????}
          ????public?void?print()?{
          ????????System.out.println("Address?book?has?"?+?people.size()?+?"?entries");

          ????????for(Iterator?i?=?people.iterator();?i.hasNext();?)?{
          ????????????Person?p?=?(Person)?i.next();
          ????????????p.print();
          ????????}
          ????}
          }
          ************AddressBookDigester*********
          import?org.apache.commons.digester.Digester;
          /**
          ?*?Usage:?java?Example1?example.xml
          ?*/
          public?class?AddressBookDigester?{
          ????public?static?void?main(String[]?args)?{
          ????????if?(args.length?!=?1)?{
          ????????????usage();
          ????????????System.exit(-1);
          ????????}
          ????????String?filename?=?args[0];
          ????????//?創(chuàng)建一個(gè)Digester實(shí)例
          ????????Digester?d?=?new?Digester();
          ????????//?創(chuàng)建AddressBook實(shí)例,并將其壓入棧頂。
          ????????AddressBook?book?=?new?AddressBook();
          ????????d.push(book);
          ????????//?增加規(guī)則
          ????????addRules(d);
          ????????//?處理輸入的xml文件
          ????????try?{
          ????????????java.io.File?srcfile?=?new?java.io.File(filename);
          ????????????d.parse(srcfile);
          ????????}
          ????????catch(java.io.IOException?ioe)?{
          ????????????System.out.println("Error?reading?input?file:"?+?ioe.getMessage());
          ????????????System.exit(-1);
          ????????}
          ????????catch( org.xml.sax.SAXException?se)?{
          ????????????System.out.println("Error?parsing?input?file:"?+?se.getMessage());
          ????????????System.exit(-1);
          ????????}
          ????????
          ????????
          ????????//?將解析出的地址數(shù)據(jù)打印出來
          ????????book.print();
          ????}
          ????
          ????private?static?void?addRules(Digester?d)?{
          ????????//?當(dāng)遇到<person>時(shí),創(chuàng)建類Person的一個(gè)實(shí)例,并將其壓入棧頂
          ????????d.addObjectCreate("address-book/person",?Person.class);
          ????????
          ????????//?將<person>標(biāo)簽的屬性(attribute)與棧頂Person類對(duì)象的屬性(property)設(shè)置方法根據(jù)各自的名字進(jìn)行映射,(例如,將標(biāo)簽屬性id與屬性設(shè)置方法setId進(jìn)行映射,將標(biāo)簽屬性category與屬性設(shè)置方法setCategory進(jìn)行映射),然后將屬性的值作參數(shù)傳遞給執(zhí)行相應(yīng)的方法。
          ????????//?如果某標(biāo)簽屬性沒法通過名字找到相應(yīng)的屬性設(shè)置方法,則此標(biāo)簽屬性被忽略(如example.xml中第一個(gè)<person>的try屬性)。
          ????????d.addSetProperties("address-book/person");

          ????????//?調(diào)用第二棧頂對(duì)象(AddressBook實(shí)例)的addPerson方法,以棧對(duì)象(Person實(shí)例)的對(duì)象為參數(shù)
          ????????d.addSetNext("address-book/person",?"addPerson");????????
          ????????
          ????????//?當(dāng)遇到<person>的子元素<name>時(shí),調(diào)用棧頂對(duì)象(Person實(shí)例)的setName方法。
          ????????//?此處addCallMethod方法的第一參數(shù)是規(guī)則,第二個(gè)參數(shù)是方法的名字,第三個(gè)是參數(shù)的數(shù)量(為0時(shí),表示只有一個(gè)參數(shù),且參數(shù)的值是元素的內(nèi)容)
          ????????d.addCallMethod("address-book/person/name",?"setName",?0);
          ????????
          ????????//?當(dāng)遇到<person>的子元素<email>時(shí),調(diào)用棧頂對(duì)象(Person實(shí)例)的addEmail 方法,addEmail方法有兩個(gè)參數(shù),取值分別來自<email>的屬性type的值和<email>本身的內(nèi)容。
          ????????//?此處addCallParam方法的第一參數(shù)是規(guī)則,第二個(gè)參數(shù)是指明被調(diào)用方法(addEmail)參數(shù)的序號(hào),第三個(gè)是參數(shù)為字符串時(shí)指屬性的名字)
          ????????d.addCallMethod("address-book/person/email",?"addEmail",?2);
          ????????d.addCallParam("address-book/person/email",?0,?"type");
          ????????d.addCallParam("address-book/person/email",?1);
          ????}

          ????private?static?void?usage()?{
          ????????System.out.println("Usage:?java?Example1?example.xml");
          ????}
          }

          運(yùn)行結(jié)果如下(運(yùn)行時(shí)可能需要xml-crimson ,一個(gè)源sun的XML解析器,可到http://xml.apache.org/crimson/下載)
          Address?book?has?2?entries
          Person?#1
          ??category=acquaintance
          ??name=Gonzo
          ??email?(type?business)?:?gonzo@muppets.com
          Person?#2
          ??category=rolemodel
          ??name=Kermit
          ??email?(type?business)?:?kermit@muppets.com
          ??email?(type?home)?:?kermie@acme.com

          Digester學(xué)習(xí)筆記(三)

            總覺得,Digester不僅僅能作配置文件解析,而且可以作得更多。

          配置屬性

            Digester用來解析應(yīng)用系統(tǒng)的配置文件,其本身也有很可配置的屬性。
          屬性描述
          classLoader 指定類裝載器(class loader)。ObjectCreateRule 和 FactoryCreateRule兩個(gè)規(guī)則中,需要?jiǎng)討B(tài)加載一些類(如那些盛放XML解析出來的數(shù)據(jù)的javaBean等),裝載器可以在次指定。如果不指定,對(duì)這此類的加載將會(huì)利用線程上下文中的加載器(當(dāng)useContextClassLoader值為真時(shí))或利用加載Digester的那個(gè)加載器。
          errorHandler 指定 SAX ErrorHandler,以在出現(xiàn)此類錯(cuò)誤時(shí)調(diào)用。默認(rèn)情況下,任何解析錯(cuò)誤都會(huì)被記入日志,Digest會(huì)繼續(xù)進(jìn)行解析。
          namespaceAware 一個(gè)布爾值,為真時(shí)對(duì)XML文件的解析時(shí)會(huì)考慮元素的域名空間(如不同的域名空間的同名元素會(huì)視為不同的元素)
          ruleNamespaceURI 指定后續(xù)加入的規(guī)則所屬的命名空間,如果此值為null,則加入的規(guī)則不與任何命名空間相聯(lián)系。
          rules 設(shè)定規(guī)則模板與XML元素的匹配處理程序。由于這個(gè)匹配程序是插件式的,所以匹配工作的完成可以用用戶定義的匹配程序未完成。默認(rèn)情況下,使用Digester提供的匹配器。
          useContextClassLoader 一個(gè)布爾值,為真時(shí)FactoryCreateRule 和 ObjectCreateRule 兩個(gè)規(guī)則中對(duì)類的裝載將會(huì)采用當(dāng)前線程上下文中指定的加載器。默認(rèn)情況下,對(duì)類的動(dòng)態(tài)加載會(huì)利用加載 Digester的那個(gè)裝載器。
          validating 一個(gè)布爾值,為真時(shí)解析器會(huì)根據(jù)DTD內(nèi)容對(duì)XML文檔進(jìn)行合法性檢查,默認(rèn)值是假,解析器只是檢查XML是否格式良好(well formed).

            除了上述屬性外,還可以注冊(cè)一個(gè)本地DTD,以供DOCTYPE聲明引用。這樣的注冊(cè)告訴XML解析器,當(dāng)遇到DOCTYPE聲明時(shí),應(yīng)使用剛注冊(cè)的DTD的內(nèi)容,而不是DOCTYPE聲明中的標(biāo)識(shí)符(identifier)。
            例如,Struect框架控制器中,使用下述的注冊(cè),告訴Structs使用一個(gè)本地的DTD中的相關(guān)內(nèi)容來處理Structs配置文件,這樣可以適用于那些沒有連接到互聯(lián)網(wǎng)的應(yīng)用環(huán)境,而在連到互聯(lián)網(wǎng)的環(huán)境中可以加快運(yùn)行速度(因?yàn)樗苊饬送ㄟ^網(wǎng)絡(luò)去取相關(guān)的資源)。URL url = new URL("/org/apache/struts/resources/struts-config_1_0.dtd");
          digester.register("-//Apache Software Foundation//DTD Struts Configuration 1.0//EN",url.toString());

          規(guī)則集打包


            通常情況下,一個(gè)規(guī)則被創(chuàng)建后,接著便注冊(cè),然后等在event時(shí)被調(diào)用,這些規(guī)則集很難為其它應(yīng)用程序直接復(fù)用。一個(gè)解決方法是將所有規(guī)則都放在一個(gè)類中,此由這些規(guī)則可以很簡(jiǎn)單地被裝載然后被注冊(cè)使用。RuleSet接口就是為些而設(shè)計(jì),一般是通過擴(kuò)展RuleSetBase類來開發(fā)規(guī)則集類。如例:
          public?class?MyRuleSet?extends?RuleSetBase?{
          ??public?MyRuleSet()?{
          ????this("");
          ??}
          ??public?MyRuleSet(String?prefix)?{
          ????super();
          ????this.prefix?=?prefix;
          ????this.namespaceURI ?=?"http://www.mycompany.com/MyNamespace";
          ??}
          ??protected?String?prefix?=?null;
          ??public?void?addRuleInstances(Digester?digester)?{
          ????digester.addObjectCreate(prefix?+?"foo/bar",
          ??????"com.mycompany.MyFoo");
          ????digester.addSetProperties(prefix?+?"foo/bar");
          ??}
          }
          可以這樣使用這個(gè)規(guī)則集
          Digesterdigester = new Digester();
          ... 一些配置Digester ...
          digester.addRuleSet(new MyRuleSet("baz/"));

          帶命名空間的XML解析


            這種情況下,使用Digester的步驟為:
          1. Digester初始化部分,指明要考慮命名空間。
            digester.setNamespaceAware(true);

          2. 指明一些規(guī)則的命名空間,如
            digester.setRuleNamespaceURI(" http://www.mycompany.com/MyNamespace");

          3. 接下來定義一些與此命名空間有關(guān)的規(guī)則,此時(shí)可以省卻前綴,如
            digester.addObjectCreate("foo/bar", "com.mycompany.MyFoo");
            digester.addSetProperties("foo/bar");

          4. 對(duì)其它命名空間,重復(fù)前面的2步

            另外,在指明要digester考慮命名空間之后,在定義匹配模板時(shí),可以將命名空間別名加":"作為元素名稱的一部分使用。這與無命名空間時(shí)是一致的。

          開發(fā)定制的匹配處理過程


            通過實(shí)現(xiàn) org.apache.commons.digester.Rules接口或擴(kuò)展org.apache.commons.digester.RulesBase類來達(dá)到定制匹配過程的目的。
            Digester提供ExtendedBaseRules來擴(kuò)展了匹配模板的定義,引入了特殊通配字符?和*以及!,提供RegexRules來支持以正則式的語法定義匹配模板,提供WithDefaultsRulesWrapper來支持默認(rèn)規(guī)則(即其它規(guī)則都不匹配時(shí)的處理規(guī) 則)。

          一些認(rèn)識(shí)


            通過看說明材料,尤其在學(xué)習(xí)Digester包中的Catalog例子以后,有一些認(rèn)識(shí):
            1、由于xml對(duì)屬性名字的定義要求,與Java中對(duì)方法名字的定義要求不一致,導(dǎo)致出現(xiàn)不能自動(dòng)映射的情況,如year-made標(biāo)簽屬性,就不可能有方法setYear-made;
            2、對(duì)于根元素,與其子元素建立聯(lián)系,有幾種辦法:一種是先生成根元素實(shí)例,壓入棧,然后解析,將調(diào)用方法規(guī)則建立聯(lián)系;另一種是解析的過程中第一個(gè)創(chuàng)建它,然后用getRoot的方法得到。
            3、如果某對(duì)象類構(gòu)造都要參數(shù),則此時(shí)需要擴(kuò)展AbstractObjectCreationFactory類為這種對(duì)象建立一個(gè)Factory,在這個(gè)Factory中取得初始化參數(shù)值然后再創(chuàng)建一個(gè)對(duì)象實(shí)例。
            4、設(shè)有某個(gè)標(biāo)簽,要想自動(dòng)用該標(biāo)簽子元素的內(nèi)容填充該標(biāo)簽對(duì)應(yīng)的對(duì)象的屬性,則需要用digester.setRules(new ExtendedBaseRules()),然后addRules(),然后再調(diào)用addBeanPropertySetter ("bala/lala/?");進(jìn)行規(guī)則定義,注意此模板中有通配符。
            5、如果對(duì)象的屬性是整型,則Digester自動(dòng)將xml文件中字符串值轉(zhuǎn)換為整型。
            6、在指明要digester考慮命名空間之后,如果不會(huì)引起歧義,完全可以忽略命名空間的存在,除非你要針對(duì)特定的命名空間進(jìn)行特定的處理。
          posted on 2006-03-28 13:20 閱讀(509) 評(píng)論(0)  編輯  收藏

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


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 方城县| 东莞市| 昭觉县| 临澧县| 漳平市| 金坛市| 六安市| 汉阴县| 德钦县| 肇源县| 昌都县| 逊克县| 通化市| 开阳县| 南郑县| 满洲里市| 荥经县| 邯郸市| 扎鲁特旗| 绍兴县| 阜宁县| 大余县| 宣恩县| 安顺市| 临安市| 古交市| 巴林左旗| 兴和县| 邯郸县| 从江县| 禹州市| 临汾市| 金川县| 尤溪县| 萝北县| 台北县| 休宁县| 鄄城县| 且末县| 永和县| 文成县|