digester的詳細講解

使用Apache Commons Digester
    本文主要參考了The serverside上的一篇文章。描述了2種典型的使用digester的方法,以及所需要注意的地方。詳細內容請參見正文。
Apache Commons Digester
簡化xml文件處理,它依賴的組件:BeanUtils、Logging、Collections。
基本概念
1. 在Digester的內部採用SAX來解析XML文件。爲了能夠正確的使用它,必須在解析之前進行相應的設置。同時,在解析xml文件的過程中,它使用Stack來保存和檢索這個期間產生的對象。
2. 爲了簡化使用,它通過匹配模式來定位要解析的xml標籤。匹配模式的例子如下:
xml文件:
<?xml version="1.0"?>
<students>
<student>
<name>Java Boy</name>
<course>JSP</course>
</student>
<student>
<name>Java Girl</name>
<course>EJB</course>
</student>
</students>
每個標籤與相應的匹配模式對應如下表:
標籤
匹配模式
<students>
students
<student>
students/student
<name>
students/student/name
<course>
students/student/course
如果將xml文件結構視爲一顆樹的話,那麼每個標籤的匹配模式就是從根元素到這個元素的路徑。除了使用具體的標籤,還可以使用通配符。
3. 使用匹配模式可以很方便的定位需要處理的元素,爲了處理這些元素,需要定義處理規則。規則在匹配模式被找到時起作用。所有的規則都是從org.apache.commons.digester.Rule派生的。所有已定義的Rule對象,可以在org.apache.commons.digester中找到。常用的規則:
- ObjectCreate,創建對象實例。
- SetProperties,將標籤屬性(Attribute)與要創建的對象的屬性相關聯。
- BeanPropertySetter,將標籤所包含標籤與要創建的對象的屬性相關聯。
- SetNext,設置遇到下一個標籤時的動作。
- CallMethod,設置當匹配模式被找到時要調用的方法。
- CallParam,設置對應的callMethod中指定方法所需要的參數值。
基本使用
以正確的順序調用Digester方法是成功使用Digester處理XML文件的關鍵。使用步驟如下:
1. 創建org.apache.commons.digester.Digester實例並配置,包括設置實現Digester Rule的對象。
2. 使用Digester的push方法在Digester使用的stack中放置一個初始對象。在解析xml文件的過程中,Digester使用stack來保存它所找到的對象。第一個對象在遇到第一個標籤時被放置到stack中,當最後一個標籤處理完畢時被彈出。爲了最後能檢索到這個對象,因此需要一個初始對象來保留一個指向它的引用。
3. 註冊匹配模式和rule。
4. 調用parse來解析xml文件。
使用舉例
1. 簡單例子,從一個xml文件中創建對象。
XML文件:
<?xml version="1.0" encoding="UTF-8"?>
<students>
<student>
<name>Java Boy</name>
<course>JSP</course>
</student>
<student>
<name>Java Girl</name>
<course>EJB</course>
</student>
</students>
要創建的對象:
public class Student {
private String name;
private String course;
……
}
解析:
public class DigesterStudy {
private Vector students;
public DigesterStudy(){
students= new Vector( 5);
}
public static void main(String[] args) {
DigesterStudy ds= new DigesterStudy();
ds.digest();
}
public void digest(){
//創建實例
Digester digester= new Digester();
//將初始對象壓入digester的stack
digester.push( this);
//指明匹配模式和要創建的類
digester.addObjectCreate( "students/student", Student.class);
//設置對象屬性
digester.addBeanPropertySetter( "students/student/name");
digester.addBeanPropertySetter( "students/student/course");
//當移動到下一個標籤中時的動作
digester.addSetNext( "students/student", "addStudent");
try {
//解析
DigesterStudy ds= (DigesterStudy)digester.parse( getClass()
.getClassLoader()
.getResourceAsStream( "students.xml"));
System.out.print( ds);
} catch (Exception e) {
e.printStackTrace();
  }
}
public void addStudent( Student student){
students.add( student);
}
public String toString(){
return students.toString();
}
}
2. 複雜例子,從xml文件中創建相互之間有關係的對象。
XML文件:
<?xml version="1.0" encoding="UTF-8"?>
<academy name="JAcademy" >
<student name="JavaBoy" division="A">
<course>
<id>C1</id>
<name>JSP</name>
</course>
<course>
<id>C2</id>
<name>Servlets</name>
</course>
</student>
<student name="JavaGirl" division="B">
<course>
<id>C3</id>
<name>EJB</name>
</course>
</student>
<teacher name="JavaGuru">
<certification>SCJP</certification>
<certification>SCWCD</certification>
</teacher>
<teacher name="JavaMaster">
<certification>OCP</certification>
<certification>SCJP</certification>
<certification>SCEA</certification>
</teacher>
</academy>
要創建的對象:
public class Academy {
private String name;
private Vector students;
private Vector teachers;
……
}
public class Student {
private String name;
private String division;
private Vector courses;
……
}
public class Course {
private String id;
private String name;
……
}
public class Teacher {
private String name;
private Vector certifications;
……
}
其中的<certification>在程序中對應一個字符串,故而沒有列出。
解析:
public void digest(){
Digester digester= new Digester();
//注意,此處並沒有象上例一樣使用push,是因爲此處從根元素創建了一個對//象實例
digester.addObjectCreate( "academy", Academy.class);
//將< academy >的屬性與對象的屬性關聯
digester.addSetProperties( "academy");

digester.addObjectCreate( "academy/student", Student.class);
digester.addSetProperties( "academy/student");

digester.addObjectCreate( "academy/student/course", Course.class);
digester.addBeanPropertySetter( "academy/student/course/id");
digester.addBeanPropertySetter( "academy/student/course/name");
digester.addSetNext( "academy/student/course", "addCourse");

digester.addSetNext( "academy/student", "addStudent");

digester.addObjectCreate( "academy/teacher", Teacher.class);
digester.addSetProperties( "academy/teacher");
//當遇到academy/teacher/certification時,調用addCertification
digester.addCallMethod( "academy/teacher/certification",
"addCertification", 1);
//設置addCertification的參數值,此處的0表示這個元素體的第一個值
//爲參數值傳入addCertification。在此處,即爲<certification>的值。
//(因爲就只有一個)
digester.addCallParam( "academy/teacher/certification", 0);
digester.addSetNext( "academy/teacher", "addTeacher");
try {
  Academy a= (Academy)digester.parse( getClass()
.getClassLoader()
.getResourceAsStream( "students.xml"));
System.out.print( a);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
3. 從配置文件中創建Digester,通過DigesterLoader可以從配置文件中創建Digester實例,從而省去類似於上例手工配置Digester的代碼。
Digester的配置文件,對應上例的配置文件如下:
<?xml version="1.0"?>
<digester-rules>
<pattern value="academy">
<object-create-rule classname="Academy" />
<set-properties-rule />
<pattern value="student">
<object-create-rule classname="Student" />
<set-properties-rule />
<pattern value="course">
<object-create-rule classname="Course" />
<bean-property-setter-rule pattern="id"/>
<bean-property-setter-rule pattern="name"/>
<set-next-rule methodname="addCourse" />
</pattern>
<set-next-rule methodname="addStudent" />
</pattern>
<pattern value="teacher">
<object-create-rule classname="Teacher" />
<set-properties-rule />
<call-method-rule pattern="certification" methodname="addCertification"
paramcount="1" />
<call-param-rule pattern="certification" paramnumber="0"/>
<set-next-rule methodname="addTeacher" />
</pattern>
</pattern>
</digester-rules>
使用配置文件之後,上例的代碼變爲:
Digester digester = DigesterLoader.createDigester(
this.getClass().getClassLoader().getResource("academyRules.xml"));
Academy a= (Academy)digester.parse( getClass()
.getClassLoader().getResourceAsStream( "students.xml"));
注意
在使用Digester需要注意的地方:
- 調用順序,正確的調用順序才能得出正確的結果。方法調用順序基本和標籤在xml文件中的層次關係相對應。基本的順序是:先創建對象;然後設置屬性;隨後處理子元素;最後設置遇到下一個元素所對應的動作。對於子元素的處理,是同樣的過程。
- 正確的使用初始對象。對比上面2個例子,之所以在第一個例子中顯示的調用了digester的push方法,其原因就在於我們並沒有如第二個例子一樣用xml的root元素創建一個實例。如果不顯式的調用,我們將會丟失這個元素的引用,那麼也就無法得到後續的對象。
- digester的addSetNex方法中所指定的方法實際上是包含匹配模式對應標籤的父標籤對應對象的方法。在上兩個例子中addStudent,都是包含Student對象的那個對象的方法。對於第一個例子,是DigesterStudy;對於第二個例子,是Academy。而且它的位置通常是在創建對象語句組的最後,與addObjectCreate相對應。在這2個語句之間的代碼中所指定的方法都是所創建對象的方法。而且它們的順序與匹配模式所對應的標籤的順序必須是一致的。
- 使用配置文件來創建digester,這樣會帶來很大的靈活性。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章