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