http://hi.baidu.com/python811022/blog/item/5ed31dcee519243ab700c86c.html
Digester框架屬于Jakarta Commons,它以規(guī)則和模式為基礎(chǔ)處理XML文檔。與SAX和DOM之類的標準API相比,Digester不涉及太多的細節(jié)問題,非常適合于對XML文檔進行簡單的處理。
在Java和XML開發(fā)中,一個常見的任務(wù)是把XML文檔轉(zhuǎn)換成對應(yīng)的Java Bean對象的層次結(jié)構(gòu)。人們經(jīng)常用標準的SAX和DOM API來完成這個任務(wù)。雖然這兩種API都很強大和靈活,但對于某些簡單的任務(wù)來說,它們顯得操作層次太低,也就是說,涉及了太多的細節(jié)問題。Jakarta Digester框架能夠很好地滿足這類場合的需要。
Jakarta的Digester框架從Struts框架發(fā)展而來,原先被用來處理struts-config.xml配置文件,但很快人們認識到它有著更廣泛的用途,把它轉(zhuǎn)入了Jakarta Commons項目。Jakarta Commons的目標是提供一個“可重用Java組件的倉庫”。Digester最新的版本是1.3,于2002年8月13日發(fā)布。
Digester框架允許開發(fā)者指定一組動作,當(dāng)解析器在XML文檔中發(fā)現(xiàn)某些特定的簡單模式時動作被執(zhí)行。Digester框架帶有10個預(yù)定義的規(guī)則(Rule),涵蓋了unmarshalling XML(例如創(chuàng)建Bean或設(shè)置Bean屬性)的大多數(shù)需求( marshalling的原意是指“配制整齊,編組列車”,marshalling是在內(nèi)存中為Java對象生成XML描述文檔的過程,而unmarshalling是指把XML形式的描述轉(zhuǎn)換到可用Java代碼操作的對象的過程,我們稱之為“反配制”),但必要時用戶可以定義和實現(xiàn)自己的規(guī)則。
在本文的例子中,我們將反配制下面這個XML文檔:
<?xml version="1.0"?> |
下面是Bean的代碼。注意使用Digester框架時,Bean類必須定義成public。
import java.util.Vector; |
Digester框架以模式(Pattern)和規(guī)則(Rule)為基礎(chǔ)處理輸入的XML。模式必須與XML元素匹配,包括其名字和在文檔樹內(nèi)的位置。描述匹配模式的語法類似于XPath匹配模式,例如:catalog模式匹配頂層的 所有的模式都必須指定其完整名稱——從根元素開始的完整路徑。唯一的例外是包含通配符(“*”)的模式,例如*/name模式匹配XML文檔內(nèi)任何位置的 當(dāng)Digester發(fā)現(xiàn)一個指定的模式,它就執(zhí)行關(guān)聯(lián)的任務(wù)。由此可見,Digester框架顯然與SAX解析器有著密切的關(guān)系(實際上,Digester類實現(xiàn)了org.xml.sax.ContentHandler,并維護著解析棧)。所有在Digester中使用的規(guī)則必須擴展org.apache.commons.digester.Rule,后者本身提供了一些類似于SAX的ContentHandler回調(diào)函數(shù)的方法。例如,當(dāng)遇到匹配元素的開始標記和結(jié)束標記時,begin()方法和end()方法將分別被調(diào)用。 一旦遇到匹配元素的內(nèi)容,body()方法被調(diào)用;最后被調(diào)用的方法是finish(),這個方法在匹配元素的結(jié)束標記處理完畢之后被調(diào)用,用來執(zhí)行可能需要的事后清理任務(wù)。然而,大多數(shù)時候我們不必關(guān)注這些方法,因為框架提供的標準規(guī)則很可能已經(jīng)提供了所有必需的功能。 要反配制一個文檔,首先創(chuàng)建一個org.apache.commons.digester.Digester類的實例,如果必要的話,進行一些配置操作,指定必需的模式和規(guī)則,最后向parse()方法傳遞一個XML文件的引用。下面的DigesterDriver示范了這一處理過程(必須在命令行上指定輸入XML文檔的名稱)。
在上面的代碼中,我們首先創(chuàng)建了Digester類的一個實例digester,然后指定它不要用DTD驗證XML文檔的合法性——這是因為我們沒有為XML文檔定義DTD。接下來,我們指定了模式和關(guān)聯(lián)的規(guī)則:ObjectCreateRule創(chuàng)建指定類的一個實例,并將它壓入解析棧。SetPropertiesRule把Bean屬性設(shè)置成當(dāng)前XML元素的屬性值——規(guī)則的第一個參數(shù)是XML屬性的名稱,第二個參數(shù)是Bean屬性的名稱。 SetPropertiesRule獲取的是XML屬性的值,而BeanPropertySetterRule獲取的是位于當(dāng)前元素內(nèi)的原始字符數(shù)據(jù)值。使用BeanPropertySetterRule時不必指定要設(shè)置的Bean屬性名字,默認是當(dāng)前XML元素的名稱。在上面的例子中,在匹配catalog/magazine/article/headline模式的規(guī)則定義中使用的就是默認值。最后,SetNextRule彈出解析棧頂部的對象,并把該對象傳遞給它下面對象的指定名稱的方法——通常用來把一個配置完畢的Bean插入父對象。 注意,我們可以為同一個模式注冊多個規(guī)則。如果注冊了多個規(guī)則,則這些規(guī)則按照它們被加入到Digester的次序執(zhí)行,例如,如果要處理catalog/magazine/article的元素,我們首先創(chuàng)建合適的article Bean,然后設(shè)置page屬性,最后彈出完成后的article Bean,并把它插入magazine。 我們不僅可以設(shè)置Bean的屬性,而且還可以調(diào)用堆棧內(nèi)對象的任意方法。這通過CallMethodRule完成,我們只需指定方法名字,如有必要,再說明調(diào)用的參數(shù)類型和數(shù)量。CallParamRule用來定義傳遞給被調(diào)用函數(shù)的參數(shù)值,參數(shù)值可以從當(dāng)前XML元素的命名的屬性獲取,也可以從當(dāng)前元素包含的原始字符數(shù)據(jù)獲取。例如,在前面實現(xiàn)DigesterDriver的例子中,我們可以不用BeanPropertySetterRule,而是通過顯式調(diào)用屬性的set方法達到同樣的目的:
上面的第一行代碼給出了要調(diào)用的方法(即setAuthor()),以及該調(diào)用需要的參數(shù)數(shù)量(即1)。第二行代碼的意思是從 這里必須注意的是,“digester.addCallMethod( "pattern", "methodName", 0 );”這個語句不是指定了一個不帶參數(shù)的方法調(diào)用,而是指定了帶有一個參數(shù)的方法調(diào)用,它的值就是當(dāng)前XML元素的字符數(shù)據(jù)!這樣,我們又有了另一種替代BeanPropertySetterRule的辦法:
如果要調(diào)用一個確實沒有參數(shù)的方法,必須采用如下形式:digester.addCallMethod( "pattern", "methodName" );。 下面簡要說明所有標準規(guī)則。 創(chuàng)建 ObjectCreateRule:利用指定類的默認構(gòu)造函數(shù),創(chuàng)建該類的一個對象,并把對象壓入棧。當(dāng)元素處理結(jié)束時,對象被彈出。被實例化的類可通過class對象或類的全稱給出。 FactoryCreateRule:利用指定的工廠類創(chuàng)建一個對象,把對象壓入棧。對于沒有提供默認構(gòu)造函數(shù)的類,這一規(guī)則很有用。用于該規(guī)則的工廠類必須實現(xiàn)org.apache.commons.digester.ObjectCreationFactory接口。 設(shè)置屬性 SetPropertiesRule:利用指定名稱的XML元素屬性值,設(shè)置頂層Bean的一個或者多個指定名稱的屬性。XML元素的屬性名稱和Bean的屬性名稱以String[]數(shù)組形式傳入該規(guī)則(通常用來處理之類的結(jié)構(gòu))。 BeanPropertySetterRule:把頂層Bean的指定名稱的屬性設(shè)置成當(dāng)前XML元素包含的字符數(shù)據(jù)。(通常用來處理 SetPropertyRule:設(shè)置頂層Bean的一個屬性。無論是Bean屬性的名稱,還是賦予該屬性的值,都在當(dāng)前XML元素中以屬性的形式指定,例如: 管理父/子關(guān)系 SetNextRule:彈出棧頂?shù)膶ο螅阉鼈鬟f給緊接其下的另一個對象的指定名稱的方法。通常用來把一個已經(jīng)初始化的Bean插入到父對象。 SetTopRule:把棧里面上數(shù)第二的對象傳遞給頂層的對象。當(dāng)子對象提供了一個setParenet方法時,這一規(guī)則很有用。 SetRootRule:調(diào)用棧底對象的一個方法,并把棧頂?shù)膶ο笞鳛閰?shù)傳入。 調(diào)用任意方法 CallMethodRule:調(diào)用頂層Bean的指定名稱的方法。被調(diào)用的方法可以有任意多個參數(shù),參數(shù)的值通過后繼的CallParamRule給出。 CallParamRule:表示方法調(diào)用的參數(shù)。參數(shù)的值或者取自指定名稱的XML元素的屬性,或者是當(dāng)前元素包含的原始字符數(shù)據(jù)。這個規(guī)則要求用一個整數(shù)指定它在參數(shù)列表中的位置。 在前面的內(nèi)容中,我們用程序代碼的方式指定模式和規(guī)則,這些模式和規(guī)則都是在編譯的時候就已經(jīng)確定,雖然從概念上來講比較簡單,但卻不能說盡善盡美:Digester框架的總體目標是在運行時識別和處理各種數(shù)據(jù)結(jié)構(gòu),但如果我們用編程的方法指定模式和規(guī)則,則所有行為在編譯時已經(jīng)固定!如果Java源程序中包含了大量固定的字符串,通常意味著程序在執(zhí)行某些配置操作,這部分操作可以被(或許是應(yīng)該被)延遲到運行時進行。 org.apache.commons.digester.xmlrules包解決了這個問題。這個包提供了一個DigesterLoader類,它能夠從XML文檔讀取模式/規(guī)則對,返回配置好的Digester對象。用來配置Digester對象的XML文檔必須遵從digester-rules.dtd,這個DTD是xmlrules包的一部分。 下面就是本文例子的配置文件rules.xml。有幾點必須說明。 首先,模式可以用兩種方式指定:或者使用
現(xiàn)在,所有實際的操作都轉(zhuǎn)移到了Digester和DigesterLoader類,XmlRulesDriver類就變得相當(dāng)簡單。運行下面的XmlRulesDriver時,在第一個命令行參數(shù)中指定目錄文檔的名字,在第二個參數(shù)中指定rules.xml(注意,DigesterLoader不是從File或者org.xml.sax.InputSource讀取rules.xml文件,而是要求指定一個URL,因此,下面代碼中File引用被轉(zhuǎn)換成了等價的URL)。
結(jié)束語:本文對Jakarta Commons Digester的介紹就到這里結(jié)束。當(dāng)然,還有許多內(nèi)容這里尚未涉及。其中一個在這里忽略的主題是XML名稱空間:Digester允許把規(guī)則定義成只能對某一個名稱空間內(nèi)定義的元素起作用。 另外,我們簡單地提及了通過擴展Rule類開發(fā)定制規(guī)則的問題。按照習(xí)慣,Digester類提供了push()、peek()和pop()方法,使得開發(fā)者能夠自由地直接操作解析棧。 參考: Jakarta Commons Digester Homepage Jakarta Struts Homepage |