Digester学习笔记
作者:kongxx
简介Digester是Apache组织下的一个子项目(jakarta/commons/),主要功能是通过读取XML文件来初始化Java对象。
目前项目的版本是1.6,网站地址http://jakarta.apache.org/commons/digester。
一个小例子此例子来源于Digester的官方网站,在这里做了一点修改。
本例子包括两个JavaBean(Foo和Bar),一个xml文件和一个测试类。
Foo.java
package test1;
import java.util.HashMap; import java.util.Iterator; import java.util.Map;
public class Foo {
private String name;
private Map bars = new HashMap();
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public void addBar(Bar bar) { if(bar == null) { throw new IllegalArgumentException("The bar is null!"); } bars.put(bar.getId() ,bar); }
public Bar findBar(String id) { return (Bar)bars.get(id); }
public Iterator getBars() { return bars.values().iterator(); }
public String toString() { StringBuffer sb = new StringBuffer(); sb.append("Foo:").append(name).append("/n"); for(Iterator i = getBars() ; i.hasNext();) { sb.append("/t").append((Bar)i.next()).append("/n"); } return sb.toString(); } } |
Bar.java
package test1;
public class Bar { private String id ; private String title ; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String toString() { StringBuffer sb = new StringBuffer(); sb.append("Bar[").append("id:").append(id).append(",title:").append(title).append("]"); return sb.toString(); } } |
test.xml
<?xml version="1.0" encoding="GB2312"?> <foo name="The Parent"> <bar id="first" title="The First Child" /> <bar id="second" title="The Second Child" /> </foo> |
Test.java
package test1; import java.io.InputStream; import org.apache.commons.digester.Digester; public class Test { public static void main(String[] args) throws Exception { Digester digester = new Digester(); digester.setValidating(false);
digester.addObjectCreate("foo", Foo.class); digester.addSetProperties("foo");
digester.addObjectCreate("foo/bar", Bar.class); digester.addSetProperties("foo/bar");
digester.addSetNext("foo/bar", "addBar", Bar.class.getName());
InputStream is = Test.class.getResourceAsStream("/test1/test.xml"); Foo foo = (Foo) digester.parse(is);
System.out.println(foo.toString()); } } |
运行Test后输出如下:
Foo:The Parent Bar[id:first,title:The First Child] Bar[id:second,title:The Second Child] |
下面来简要看一下Digester的处理流程,如下;
Ø 创建一个org.apache.commons.digester.Digester
对象实例,如
Digester digester = new Digester();。
Ø 设置Digester
属性,如:
digester.setValidating(false);。
Ø 将需要初始化的对象压入Digester对象栈中(可选操作)。
Ø 注册所有符合模版(Patterns)的需要处理的元素,如:
digester.addObjectCreate("foo", Foo.class);
digester.addSetProperties("foo");
digester.addObjectCreate("foo/bar", Bar.class);
digester.addSetProperties("foo/bar");
digester.addSetNext("foo/bar", "addBar", Bar.class.getName());
Ø 执行解析操作来解析XML Document并返回一个对象堆栈的根对象,如:Foo foo = (Foo) digester.parse(is);。
对象栈通常我们使用Digester主要是用来构造一个树型的Java对象。我们可以使用一些处理规则来解析XML文档,当发现符合规则的元素的开始位置时创建一个对象并将其压入对象栈中,然后继续解析直到发现第一个结束位置,此时弹出创建的对象。
元素匹配模式Digester另一个主要特性是元素匹配模式。例如在第一个例子中的xml文件内容:
节点(元素) |
匹配模式 |
<foo name="The Parent"> <bar id="first" title="The First Child" /> <bar id="second" title="The Second Child" /> </foo> |
Foo |
foo/bar | |
foo/bar | |
|
此外,Digester也可以使用“*”来匹配特殊的节点,如“*/bar”可以匹配任意节点下的bar节点。
处理规则处理操作:
方法 |
说明 |
begin() |
在一个元素被匹配后的开始位置调用 |
body() |
元素的嵌套内容(如子元素)被识别出时被调用 |
end() |
在一个元素被匹配后的开始位置调用 |
finish() |
解析结束时被调用 |
常用处理规则:
规则名 |
说明 |
ObjectCreateRule |
创建一个新对象并将其压入对象栈中,当元素解析完毕,再从对象栈中弹出。要求创建的类有默认构造函数。 |
FactoryCreateRule |
创建一个新对象并将其压入对象栈中,当元素解析完毕,再从对象栈中弹出。和ObjectCreateRule的区别是此规则主要处理要构造的类没有默认构造函数的情况。 |
SetPropertiesRule |
设置对象属性并将其压入对象栈顶部。 |
SetPropertyRule |
设置一个对象属性并将其压入对象栈顶部。 |
SetNextRule |
调用倒数第二级(Top-1,或父对象)对象的方法,并且将顶级(Top或子对象)对象作为参数。此规则主要用来处理父子关系的对象。通常是类似“addChild”的方法。 |
SetTopRule |
调用顶部位置子对象的类似“setParent”的方法,使用(Top-1)对象作为参数。 |
CallMethodRule |
调用栈中对象(通常是栈顶对象)的方法,使用后续的 |
CallParamRule |
用来指定CallMethodRule的参数的值的来源,它可以来自一个特定的属性,或子元素的body的内容. |
NodeCreateRule |
将对象树的一部分转化为DOM的一个节点。 |
此例子是典型的递归遍历xml文档的例子。例如:在组织机构中的部门,每个部门都可以有上级部门,也可以有下级部门,因此部门的xml描述如下:
<?xml version="1.0" encoding="GB2312"?> <departments> <department id="1" name="name1"> <department id="11" name="name11"> <department id="111" name="name111"> </department> </department> <department id="12" name="name12"> </department> <department id="13" name="name13"> </department> </department> <department id="2" name="name2"> <department id="21" name="name21"> </department> <department id="22" name="name22"> </department> <department id="23" name="name23"> </department> </department> </departments> |
俩个JavaBean类和一个测试类如下:
Departments.java 对应xml文档中的根节点(departments)
package test3;
import java.util.ArrayList; import java.util.Iterator; import java.util.List;
public class Departments {
private List children = new ArrayList();
public List getChildren() { return children; }
public void setChildren(List children) { this.children = children; }
public void addChild(Department d) { this.children.add(d); }
public String toString() { StringBuffer sb = new StringBuffer(); sb.append("/n"); sb.append("<departments>/n"); for(Iterator i = children.iterator() ; i.hasNext() ;) { Department d = (Department)i.next(); sb.append(d.toString()); } sb.append("</departments>/n"); return sb.toString(); } } |
Department.java对应具体的一个部门节点
package test3;
import java.util.HashSet; import java.util.Iterator; import java.util.Set;
public class Department {
private String id;
private String name;
private Department parent;
private Set children = new HashSet();
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 Department getParent() { return parent; }
public void setParent(Department parent) { this.parent = parent; }
public Set getChildren() { return children; }
public void setChildren(Set children) { this.children = children; }
public void addChild(Department d) { this.children.add(d); }
public String toString() { StringBuffer sb = new StringBuffer(); sb.append("<department id=/"").append(id).append("/""); sb.append(" name=/"").append(name).append("/">/n"); for(Iterator i = children.iterator() ; i.hasNext() ;) { Department d = (Department)i.next(); sb.append(d.toString()); } sb.append("</department>/n"); return sb.toString(); } } |
测试代码如下:
package test3;
import java.io.InputStream;
import org.apache.commons.digester.Digester; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory;
public class Test {
private static Log log = LogFactory.getLog(Test.class);
public static void main(String[] args) throws Exception { test1(); }
private static void test1() throws Exception { InputStream is = Test.class.getResourceAsStream("/test3/department.xml");
Digester digester = new Digester(); digester.setValidating(false);
digester.addObjectCreate("departments", Departments.class); digester.addSetProperties("departments");
digester.addObjectCreate("*/department", Department.class); digester.addSetProperties("*/department");
digester.addSetNext("*/department","addChild",Department.class.getName());
Departments ds = (Departments) digester.parse(is);
log.info(ds.toString()); } } |
运行程序,输出如下:
<departments> <department id="1" name="name1"> <department id="12" name="name12"> </department> <department id="11" name="name11"> <department id="111" name="name111"> </department> </department> <department id="13" name="name13"> </department> </department> <department id="2" name="name2"> <department id="23" name="name23"> </department> <department id="21" name="name21"> </department> <department id="22" name="name22"> </department> </department> </departments> |