【XML系列】詳解Digester處理XML(一)

Digester框架屬於Jakarta Commons,它以規則和模式爲基礎處理XML文檔。與SAXDOM之類的標準API相比,Digester不涉及太多的細節問題,很是適合於對XML文檔進行簡單的處理。java

  在JavaXML開發中,一個常見的任務是把XML文檔轉換成對應的Java Bean對象的層次結構。人們常常用標準的SAX和DOM  API來完成這個任務。雖然這兩種API都很強大和靈活,但對於某些簡單的任務來講,它們顯得操做層次過低,也就是說,涉及了太多的細節問題。Jakarta Digester框架可以很好地知足這類場合的須要。     apache

Digester框架簡介數組

    

    JakartaDigester框架從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屬性)的大多數需求,但必要時用戶能夠定義和實現本身的規則。框架

marshalling的原意是指「配製整齊,編組列車」,marshalling是在內存中爲Java對象生成XML描述文檔的過程,函數

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,後者自己提供了一些相似於SAXContentHandler回調函數的方法。例如,當遇到匹配元素的開始標記和結束標記時,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);

SetPropertiesRuleBean屬性設置成當前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建立 

ObjectCreateRule:利用指定類的默認構造函數,建立該類的一個對象,並把對象壓入棧。當元素處理結束時,對象被彈出。被實例化的類可經過class對象或類的全稱給出。     

FactoryCreateRule:利用指定的工廠類建立一個對象,把對象壓入棧。對於沒有提供默認構造函數的類,這一規則頗有用。用於該規則的工廠類必須實現org.apache.commons.digester.ObjectCreationFactory接口。     

2設置屬性

SetPropertiesRule:利用指定名稱的XML元素屬性值,設置頂層Bean的一個或者多個指定名稱的屬性。XML元素的屬性名稱和Bean的屬性名稱以String[]數組形式傳入該規則(一般用來處理之類的結構)。

BeanPropertySetterRule:把頂層Bean的指定名稱的屬性設置成當前XML元素包含的字符數據。(一般用來處理<page>10</page>之類的結構)。

SetPropertyRule:設置頂層Bean的一個屬性。不管是Bean屬性的名稱,仍是賦予該屬性的值,都在當前XML元素中以屬性的形式指定,

例如:<article key="page" value="10" />

3管理父/子關係

SetNextRule:彈出棧頂的對象,把它傳遞給緊接其下的另外一個對象的指定名稱的方法。一般用來把一個已經初始化的Bean插入到父對象。 

SetTopRule:把棧裏面上數第二的對象傳遞給頂層的對象。當子對象提供了一個setParenet方法時,這一規則頗有用。 

SetRootRule:調用棧底對象的一個方法,並把棧頂的對象做爲參數傳入。 

4調用任意方法

CallMethodRule:調用頂層Bean的指定名稱的方法。被調用的方法能夠有任意多個參數,參數的值經過後繼的CallParamRule給出。     

CallParamRule:表示方法調用的參數。參數的值或者取自指定名稱的XML元素的屬性,或者是當前元素包含的原始字符數據。這個規則要求用一個整數指定它在參數列表中的位置。

相關文章
相關標籤/搜索