Commons Digester
1.6提供了將XML轉化爲對象的最簡單的方法。Digester已經由O'Reilly網站上的兩篇文章介紹過了:“學習和使用Jakarta
Digester”,作者是Philipp K. Janert,和“使用Jakarta Commons, 第二部分”,作者是Vikram
Goyal。兩篇文章都演示了XML規則集的使用,但如何在XML中定義規則集並沒有理解。大多所見到的Digester的使用是程序化地定義規則集,以
已編譯的形式。你應該避免硬編碼的Digester規則,特別是當你可以將映射信息存儲在外部文件中或一個類路徑資源中時。外部化一個Digester規
則可以更好地適應一個演化中的XML文檔結構或者說一個演化中的對象模型。
爲了演示在XML中定義規則集與硬編碼的規則集之間的區別,考慮系統解析XML給一個Person bean,包括在下面定義的屬性—id, name和age。
package org.test;
public class Person {
public String id;
public String name;
public int age;
public Person() {}
public String getId() { return id; }
public void setId(String id) {
this.id = id;
}
public String getName() { return name; }
public void setName(String name) {
this.name = name;
}
public int getAge() { return age; }
public void setAge(int age) {
this.age = age;
}
}
確認你的應用需要解析一個包含了多個person元素的XML文件。下面的XML文件,data.xml,包含了兩個person元素,你想要把它們解析到Person對象中:
<people>
<person id="1">
<name>Tom Higgins</name>
<age>25</age>
</person>
<person id="2">
<name>Barney Smith</name>
<age>75</age>
</person>
<person id="3">
<name>Susan Shields</name>
<age>53</age>
</person>
</people>
你希望如果結構和XML文件的內容在未來幾個月中變化,你不需要在已編譯的Java代碼中硬編碼XML文件的結構。爲了做到這一點,你需要在一個XML文
件中定義Digester的規則,並且它可以作爲一種資源從類路徑中裝入。下面的XML文檔,person-rules.xml,映射person元素到
Person bean:
<digester-rules>
<pattern value="people/person">
<object-create-rule classname="org.test.Person"/>
<set-next-rule methodname="add"
paramtype="java.lang.Object"/>
<set-properties-rule/>
<bean-property-setter-rule pattern="name"/>
<bean-property-setter-rule pattern="age"/>
</pattern>
</digester-rules>
上述所做的是指示Digester創建一個新的Person實例,當它遇到一個person元素時,調用add()來將Person對象加入到一個ArrayList中,設置person元素中相匹配的屬性,並從下一級元素name和age中設置name和age的屬性。
現在你已經看到了Person類,會被解析的文檔,和以XML的形式定義的Digester規則。現在你需要創建一個由person-rules.xml
定義了規則的Digester的實例。下面的代碼創建
了一個Digester,通過將person-rules.xml的URL傳遞給DigesterLoader
既然person-rules.xml文件是與解析它的類在同一個包內的類路徑資源,URL可以通過getClass().getResource()來得到。DigesterLoader然後解析規則並將它加到新創建的Digester上:
import org.apache.commons.digester.Digester;
import org.apache.commons.digester.xmlrules.DigesterLoader;
// 從XML規則集中配置Digester
URL rules = getClass().getResource("./person-rules.xml");
Digester digester =
DigesterLoader.createDigester(rules);
// 將空的List推入到Digester的堆棧
List people = new ArrayList();
digester.push( people );
// 解析XML文檔
InputStream input = new FileInputStream( "data.xml" );
digester.parse( input );
一旦Digester完成對data.xml的解析,三個Person對象將會在ArrayList people中。
與將規則定義在XML不同的方法是使用簡便的方法將它們加入到一個Digester實例中。大多數文章和例子都用這種方法,使用
addObjectCreate() 和
addBeanPropertySetter()這樣的方法來將規則加入中Digester上。下面的代碼加入了與定義在person-
rules.xml中相同的規則:
digester.addObjectCreate("people/person",
Person.class);
digester.addSetNext("people/person",
"add",
"java.lang.Object");
digester.addBeanPropertySetter("people/person",
"name");
digester.addBeanPropertySetter("people/person",
"age");
如果你曾經發現自己正在用一個有着2500行代碼的類,用SAX來解析一個巨大的XML文檔,或者使用DOM或JDOM的完整的一個集合類,你就會理解
XML的解析比它應該做的要複雜的多,就大多數情況來說。如果你正在建一個有着嚴格的速度和內存要求的高效的系統,你會需要SAX解析器的速度。如果你需
要DOM級別3的複雜度,你會需要像Apache
Xerces的解析器。但如果你只是簡單的試圖將幾個XML文檔解析到對象中去的話,看一下Commons Digester,
並把你的規則定義在一個XML文件中。
任何時候你都應該將配置信息從硬編碼中移出來。我會建議你在一個XML文件中定義規則並從文件系統或類路徑中裝入它。這樣可以使你的程序更好地適應XML
文檔以及對象模型的變化。有關在XML文件中定義Digester規則的更多的資料,參看Jakarta Commons
Cookbook一書的6.2節,“將XML文檔轉換爲對象”