Digester框架屬於Jakarta Commons,它以規則和模式爲基礎處理XML文檔。與SAX和DOM之類的標準API相比,Digester不涉及太多的細節問題,很是適合於對XML文檔進行簡單的處理。java
在Java和XML開發中,一個常見的任務是把XML文檔轉換成對應的Java Bean對象的層次結構。人們常常用標準的SAX和DOM API來完成這個任務。雖然這兩種API都很強大和靈活,但對於某些簡單的任務來講,它們顯得操做層次過低,也就是說,涉及了太多的細節問題。Jakarta Digester框架可以很好地知足這類場合的須要。 apache
Digester框架簡介數組
Jakarta的Digester框架從Struts框架發展而來,原先被用來處理struts-config.xml配置文件,但很快人們認識到它有着更普遍的用途,把它轉入了Jakarta Commons項目。Jakarta Commons的目標是提供一個「可重用Java組件的倉庫」。Digester最新的版本是1.3,於2002年8月13日發佈。app
Digester框架容許開發者指定一組動做,當解析器在XML文檔中發現某些特定的簡單模式時動做被執行。Digester框架帶有10個預約義的規則(Rule),涵蓋了unmarshalling XML(例如建立Bean或設置Bean屬性)的大多數需求,但必要時用戶能夠定義和實現本身的規則。框架
l marshalling的原意是指「配製整齊,編組列車」,marshalling是在內存中爲Java對象生成XML描述文檔的過程,函數
l unmarshalling是指把XML形式的描述轉換到可用Java代碼操做的對象的過程,咱們稱之爲「反配製」spa
在本文的例子中,咱們將反配製下面這個XML文檔: 命令行
<?xml version="1.0"?> <catalog library="somewhere"> <book> <author>Author 1</author> <title>Title 1</title> </book> <book> <author>Author 2</author> <title>His One Book</title> </book> <magazine> <name>Mag Title 1</name> <article page="5"> <headline>Some Headline</headline> </article> <article page="9"> <headline>Another Headline</headline> </article> </magazine> <book> <author>Author 2</author> <title>His Other Book</title> </book> <magazine> <name>Mag Title 2</name> <article page="17"> <headline>Second Headline</headline> </article> </magazine> </catalog>
下面是Bean的代碼。注意使用Digester框架時,Bean類必須定義成public。 code
public class Article { private String headline; private String page; public Article() { } public void setHeadline(String rhs) { headline = rhs; } public void setPage(String rhs) { page = rhs; } public String toString() { return "Article: Headline='" + headline + "' on page='" + page + "' "; } }
public class Magazine { private String name; private Vector articles; public Magazine() { articles = new Vector(); } public void setName(String rhs) { name = rhs; } public void addArticle(Article a) { articles.addElement(a); } public String toString() { StringBuffer buf = new StringBuffer("Magazine: Name='" + name + "' "); for (int i = 0; i < articles.size(); i++) { buf.append(articles.elementAt(i).toString()); } return buf.toString(); } }
public class Book { private String author; private String title; public Book() { } public void setAuthor(String rhs) { author = rhs; } public void setTitle(String rhs) { title = rhs; } public String toString() { return "Book: Author='" + author + "' Title='" + title + "'"; } }
public class Catalog { private Vector books; private Vector magazines; public Catalog() { books = new Vector(); magazines = new Vector(); } public void addBook(Book rhs) { books.addElement(rhs); } public void addMagazine(Magazine rhs) { magazines.addElement(rhs); } public String toString() { String newline = System.getProperty("line.separator"); StringBuffer buf = new StringBuffer(); buf.append("--- Books ---").append(newline); for (int i = 0; i < books.size(); i++) { buf.append(books.elementAt(i)).append(newline); } buf.append("--- Magazines ---").append(newline); for (int i = 0; i < magazines.size(); i++) { buf.append(magazines.elementAt(i)).append(newline); } return buf.toString(); } }
指定模式和規則 xml
Digester框架以模式(Pattern)和規則(Rule)爲基礎處理輸入的XML。模式必須與XML元素匹配,包括其名字和在文檔樹內的位置。描述匹配模式的語法相似於XPath匹配模式,例如:catalog模式匹配頂層的<catalog>元素,catalog/book模式匹配直接嵌套在<catalog>元素內的<book>元素(但不匹配文檔內其餘位置的<book>元素)。
全部的模式都必須指定其完整名稱——從根元素開始的完整路徑。
惟一的例外是包含通配符(「*」)的模式,例如*/name模式匹配XML文檔內任何位置的<name>元素。可是根元素沒必要特別指出,由於全部的路徑都是從根元素開始的絕對路徑。
當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示範了這一處理過程(必須在命令行上指定輸入XM`L文檔的名稱)。
public class DigesterDriver { public static void main(String[] args) { try { Digester digester = new Digester(); digester.setValidating(false); digester.addObjectCreate("catalog", Catalog.class); // xml中的<catalog>對應上類Catalog digester.addObjectCreate("catalog/book", Book.class); // xml中的<catalog><book>對應上類Book digester.addBeanPropertySetter("catalog/book/author", "author"); // xml中的<catalog><book><author>對應上類Book的author // <author>Author 2</author> digester.addBeanPropertySetter("catalog/book/title", "title"); // xml中的<catalog><book><title>對應上類Book的title digester.addSetNext("catalog/book", "addBook"); // xml中的<catalog></book>對應Catalog.addBook(),將生成的Book對象加入 digester.addObjectCreate("catalog/magazine", Magazine.class); // xml中的<catalog><magazine>對應類Magazine digester.addBeanPropertySetter("catalog/magazine/name", "name"); // xml中的<catalog><magazine><name>對應類Magazine的name digester.addObjectCreate("catalog/magazine/article", Article.class); // xml中的<catalog><magazine><article>對應類article digester.addSetProperties("catalog/magazine/article", "page", "page"); // xml中的<catalog><magazine><article page>對應類article的page digester.addBeanPropertySetter("catalog/magazine/article/headline"); digester.addSetNext("catalog/magazine/article", "addArticle"); digester.addSetNext("catalog/magazine", "addMagazine"); File input = new File(args[0]); Catalog c = (Catalog) digester.parse(input); System.out.println(c.toString()); } catch (Exception exc) { exc.printStackTrace(); } } }
在上面的代碼中,咱們首先建立了Digester類的一個實例digester,
digester.setValidating(false);
而後指定它不要用DTD驗證XML文檔的合法性——這是由於咱們沒有爲XML文檔定義DTD。接下來,咱們指定了模式和關聯的規則:ObjectCreateRule建立指定類的一個實例,並將它壓入解析棧。
digester.addObjectCreate("catalog", Catalog.class);
SetPropertiesRule把Bean屬性設置成當前XML元素的屬性值——規則的第一個參數是XML屬性的名稱,第二個參數是Bean屬性的名稱。SetPropertiesRule獲取的是XML屬性的值。
digester.addSetProperties("catalog/magazine/article", "page", "page");
或者digester.addSetProperties("database/user");它缺省將user下的屬性裝入名字相同的私有屬性中。
BeanPropertySetterRule獲取的是位於當前元素內的原始字符數據值。使用BeanPropertySetterRule時沒必要指定要設置的Bean屬性名字,默認是當前XML元素的名稱。
digester.addBeanPropertySetter("catalog/magazine/vx", "name");
在上面的例子中,在匹配catalog/magazine/article/headline模式的規則定義中使用的就是默認值。
digester.addBeanPropertySetter("catalog/magazine/article/headline");
SetNextRule彈出解析棧頂部的對象,並把該對象傳遞給它下面對象的指定名稱的方法——一般用來把一個配置完畢的Bean插入父對象。
digester.addSetNext("catalog/book", "addBook");
注意,咱們能夠爲同一個模式註冊多個規則。若是註冊了多個規則,則這些規則按照它們被加入到Digester的次序執行,例如,若是要處理catalog/magazine/article的元素,咱們首先建立合適的article Bean,而後設置page屬性,最後彈出完成後的article Bean,並把它插入magazine。
調用任意方法
咱們不只能夠設置Bean的屬性,並且還能夠調用堆棧內對象的任意方法。這經過CallMethodRule完成,咱們只需指定方法名字,若有必要,再說明調用的參數類型和數量。CallParamRule用來定義傳遞給被調用函數的參數值,參數值能夠從當前XML元素的命名的屬性獲取,也能夠從當前元素包含的原始字符數據獲取。例如,在前面實現DigesterDriver的例子中,咱們能夠不用BeanPropertySetterRule,而是經過顯式調用屬性的set方法達到一樣的目的:【setter】
digester.addCallMethod("catalog/book/author", "setAuthor", 1);
digester.addCallParam("catalog/book/author", 0);
若<author>tt</author>將tt做爲參數並調用setAuthor方法。(能夠設置多個參數)
上面的第一行代碼給出了要調用的方法(即setAuthor()),以及該調用須要的參數數量(即1)。第二行代碼的意思是從元素包含的字符數據獲取函數參數的值,把它做爲參數數組的第一個傳入(即索引是0的數組元素)。
【getter】若是咱們指定了XML元素屬性的名稱,
(例如digester.addCallParam("catalog/book/author", 0, "author");),則參數值將從當前元素的相應屬性值獲取。
這裏必須注意的是,
digester.addCallMethod("pattern", "methodName", );
這個語句不是指定了一個不帶參數的方法調用,而是指定了帶有一個參數的方法調用,它的值就是當前XML元素的字符數據!這樣,咱們又有了另外一種替代BeanPropertySetterRule的辦法:
digester.addCallMethod("catalog/book/author","setAuthor",0);
若<author>tt</author>將tt做爲參數並調用setAuthor方法。
若是要調用一個確實沒有參數的方法,必須採用以下形式:
digester.addCallMethod("pattern","methodName");。
標準規則概要
下面簡要說明全部標準規則。
1建立
n ObjectCreateRule:利用指定類的默認構造函數,建立該類的一個對象,並把對象壓入棧。當元素處理結束時,對象被彈出。被實例化的類可經過class對象或類的全稱給出。
n FactoryCreateRule:利用指定的工廠類建立一個對象,把對象壓入棧。對於沒有提供默認構造函數的類,這一規則頗有用。用於該規則的工廠類必須實現org.apache.commons.digester.ObjectCreationFactory接口。
2設置屬性
l SetPropertiesRule:利用指定名稱的XML元素屬性值,設置頂層Bean的一個或者多個指定名稱的屬性。XML元素的屬性名稱和Bean的屬性名稱以String[]數組形式傳入該規則(一般用來處理之類的結構)。
l BeanPropertySetterRule:把頂層Bean的指定名稱的屬性設置成當前XML元素包含的字符數據。(一般用來處理<page>10</page>之類的結構)。
l SetPropertyRule:設置頂層Bean的一個屬性。不管是Bean屬性的名稱,仍是賦予該屬性的值,都在當前XML元素中以屬性的形式指定,
例如:<article key="page" value="10" />。
3管理父/子關係
l SetNextRule:彈出棧頂的對象,把它傳遞給緊接其下的另外一個對象的指定名稱的方法。一般用來把一個已經初始化的Bean插入到父對象。
l SetTopRule:把棧裏面上數第二的對象傳遞給頂層的對象。當子對象提供了一個setParenet方法時,這一規則頗有用。
l SetRootRule:調用棧底對象的一個方法,並把棧頂的對象做爲參數傳入。
4調用任意方法
l CallMethodRule:調用頂層Bean的指定名稱的方法。被調用的方法能夠有任意多個參數,參數的值經過後繼的CallParamRule給出。
l CallParamRule:表示方法調用的參數。參數的值或者取自指定名稱的XML元素的屬性,或者是當前元素包含的原始字符數據。這個規則要求用一個整數指定它在參數列表中的位置。