这是我的第一篇博客,基本都是从多个博客中借鉴过来,然后按照自己的理解整理了一下写的,第一次写博客不知道该注意什么,有不好的地方请指出,非常感谢
一、前言
SAX是基于文件流来解析xml文件的,在读取xml文件流时,SAX会通过节点来触发相应的操作,也可以说SAX是基于文件流的事情触发机制来解析xml文件的。
Digeter是apache的common项目,
作用是将XML转化成对象,使用者直接从对象中获取xml的节点信息。
Digester是对SAX的包装,
它也是基于文件流来解析xml文件,只不过这些解析操作对用户是透明的。
Tomcat的配置文件conf/server.xml就是用Digester来读取的。
在tomcat源码中,Digester类所在位置为org.apache.tomcat.util.digester.Digester,它把开源组件digester的源代码拷贝了过来。
二、
digester使用
方式:
digester有两种使用方式:
-
一种为tomat内嵌的org.apache.tomcat.util.digester.Digester;
-
另一种为digester maven依赖。
本文采用第二种--maven依赖的方式。
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-digester3</artifactId>
<version>3.2</version>
</dependency>
三、
digester的使用规则
1、Digester
解析过程
分为两步
-
定义好模式(定义要匹配的标签)
-
将模式与规则(定义匹配到标签后的行为的对象)相关联
2、模式
与
规则
是什么
模式:
说白了就是xml文件的元素标签,只不过是附带了父节点的标签,
由
父元素的模式+”/”+子元素的模式
拼接而成
规则:
rule,当遇到一个模式(xml标签元素)时,需要执行相应的
一个或多个动作。简单来说 就是定义当模式匹配成功时,程序需要做什么。
注意:Digester库已经预定义了一些规则。可以直接使用这些规则而无须深入理解Rule类的实现
3、Digester
解析XML节点时的生命周期
在解析XML节点时,有一整个生命周期在里面,解析一个节点时,会有一下生命周期,
1.遇到匹配的节点的开始部分时开始解析,
2.解析文本内容,
3.遇到匹配的节点的结束部分时结束解析,
4.最后处理资源。
-
begin() :当 Digester实例匹配到某个模式的 开始标签 时调用,会将该节点的所有属性作为从参数传入。
-
body() :当读取到匹配节点的内容时调用,注意指的不是子节点,而是嵌入内容为普通文本。
-
end() : 当Digester实例匹配到某个模式的 结束标签 时 调用,如果存在子节点,只有当子节点处理完毕后该方法才会被调用。
-
finish() :当整个parse()方法完成时调用,多用于清楚临时数据和缓存数据。
4、示例
<?xml version="1.0" encoding="ISO-8859-1"?>
<employee firstName="Brian" lastName="May">
<office>
<address streeName="Wellington Street" streetNumber="110"/>
</office>
</employee>
上文文档的模式
该XML文档中的根元素是employee。employee元素有一个模式,名为employee。
office元素是employee元素的子元素,子元素的模式由该元素的父元素的模式在加上“/” 符号,以及该元素的名字拼接而成的,因此,office元素的模式是employee/office。
依次类推
address的元素的父元素是office元素。office元素的模式是 employee/office ,因此 address的模式 为 employee/office/address。
解析上文中xml文档时,Digester对象执行的操作:
-
Digester对象首先会先遇到 employee元素的开始标签,然后 Digester对象 会检查 是否有规则和模式employee相关联,若有 Digester会执行相应Rule对象的begin方法,若有多个Rule对象与该模式匹配,则按照其添加到Digester对象的顺序逐个执行;
-
然后 它会 遇到office元素的开始标签,Digester对象会检查是否有规则与模式 employee/office相关联,若有,则执行Rule的begin()方法,
-
接下来Digester会遇到address标签的开始标签,它会检查是否有规则与模式employee/office/address相关联,若有则执行它的 begin()方法。
-
接着,Digester对象会遇到 address元素的结束标签,会执行相匹配的Rule的end()方法。
-
再下来,Digester对象会遇到office元素的的结束标签,会执行相匹配的Rule对象的end()方法
-
最后,Digester对象会遇到employee元素的结束标签,会执行相匹配的Rule对象的end()方法。
四、
digester的
规则接口
1、内置的规则接口
Digester内置了一些规则,可以调用接口直接使用,还有一些其他的API可调用:
-
ObjectCreateRule : 当begin()方法调用时,该规则会将指定的Java类实例化,并将其放入对象栈。具体的Java类可由该规则在构造方法出啊如,也可以通过当前处理XML节点的某个属性指定,属性名称通过构造方法传入。当end()方法调用时,该规则创建的对象将从栈中取出。
-
FactoryCreateRule :ObJectCreateRule规则的一个变体,用于处理Java类无默认构造方法的情况,或者需要在Digester处理该对象之前执行某些操作的情况。
-
SetPropertiesRule :当begin()方法调用时,Digester使用标准的Java Bean属性操作方法(setter)将当前XML节点的属性值设置到对象栈顶部的对象中。
-
SetPropertyRule :当begin()方法调用时,Digester会设置栈顶部对象指定属性的值,其中属性名和属性值分别通过XML节点的两个属性指定。
-
SetNextRule :当end()方法调用时,Digester会找到位于栈顶部对象的下一个对象,并调用其指定的方法,同时将栈顶部对象作为参数传入,用于设置父对象的子对象,以便在栈对象之间建立父子关系,从而形成对象树,方便引用。
-
SetTopRule :与setNextRule对象,当end()方法调用时,Digester会找到位于站顶部的对象,调用其指定方法,同时将位于顶部下一个对象作为参数传入,用于设置当前对象的父对象。
-
CallMethRule :该规则用于在end()方法调用时执行栈顶对象的某个方法,参数值由CallParamRule获取。
-
CallParamRule :该规则与CallMethodRule配合使用,作为其子节点的处理规则创建方法参数,参数值可取自某个特殊属性,也可以取自节点的内容。
-
NodeCreateRule :用于将XML文档树的一部分转换为DOM节点,并放入栈。
2.自定义规则addRule(String pattern, Rule rule)
如果需要自定义规则,只需要创建一个类继承Rule接口,并重写里面的生命周期方法,可以选择只重写部分。
例如:
public
class
ConnectorCreateRule
extends
Rule
{
@Override
public
void
begin
(String namespace, String name, Attributes attributes){
//do something
}
@Override
public
void
begin
(String namespace, String name, Attributes attributes){
//do something
}
}
最后在使用自定义的规则时,方法如下:
digester.addRule("Server/Service/Connector",new ConnectorCreateRule());
此时即可。
3、规则集addRuleSet(RuleSet ruleSet)
很多时候针对同一个节点,我们会执行很多规则,比如:创建一个对象,设置属性,调用方法。至少三个。每次都写三个是比较麻烦的,那么有没有比较方便的方法呢?
有。使用
addRuleSet()
方法,传入需要匹配的节点名称,然后对该节点使用多个规则。此方法方便重用。
案例:
首先自定义一个规则:
public
class
MyRuleSet
extends
RuleSetBase {
public
MyRuleSet
(){
this
(
""
);
}
public
MyRuleSet
(String prefix){
super
();
this
.prefix = prefix;
}
protected
String prefix =
null
;
public
void
addRuleInstances
(Digester digester){
digester.addObjectCreate( prefix +
"foo/bar"
,
"com.mycompany.MyFoo"
);
digester.addSetProperties( prefix +
"foo/bar"
);
}
}
然后可以直接调用:
Digester digester =
new
Digester();
... configure Digester properties ...
digester.addRuleSet(
new
MyRuleSet(
"baz/"
) );
五、常用的方法
下面的常用方法都是对前文讲的规格的封装
如:
public void addObjectCreate(String pattern, String className) {
this.addRule(pattern, new ObjectCreateRule(className));
}
...
...
public void addSetProperties(String pattern) {
this.addRule(pattern, new SetPropertiesRule());
}
1.
addObjectCreate
该方法有4个
重载的版本
通过模式和创建对象的类进行调用
public void addObjectCreate( String pattern , Class class )
public void addObjectCreate( String pattern , String className)
设置节点与Java对象的映射规则,pattern
指定节点的筛选模式,class设置映射对象。
SAX解析时,遇到
pattern
指定的节节点,会创建一个class实例放入堆栈中。
比如:digester.addObectCreate("database/user","com.model.UserBean").解析遇到user节点时,会创建一个UserBean实例并放入堆栈中。
可以在XML中通过属性指定类进行实例化的重载
public void addObjectCreate( String pattern , String className , String attributeName )
public void addObjectCreate(String pattern , String attributeName , Class class )
下面两个方法与上面的不同是,当匹配到pattern模式时,如果指定了attributeName,则根据attributeName创建类对象;否则根据className创建类对象
2.
addSetProperties
(String pattern)
(
一般紧跟addObjectCreate使用
)
设置节点的属性设置规则。
当匹配到pattern模式
时,就
根据属性列表中的属性值对,
填充其属性
比如:digester.addSetProperties("database/user"),解析遇到user节点时,会获取键值对 userName=guest,password=guest,获得栈顶的UserBean对象,设置实例的userName、password属性;
3.
addBeanPropertySetter
(String pattern)
该方法的作用及使用方法类似于addSetProperties,只不过它是用
pattern
所指定的标签来调用对象的setter。
该方法在tomcat6中貌似没有。
tomcat6中Digester类路径为:import org.apache.tomcat.util.digester.Digester;
不为:import
org.apache.commons.digester.Digester;
4.
addSetNext (常用来把子pattern
节点注入到父pattern的实例中)
该方法有2个
重载的版本
addSetNext(String pattern,String methodName)
设置当前pattern
节点与父节点的调用规则
,当匹配到pattern模式的
结束符
时,调用父节点的methodName方法。
将栈顶元素作为次顶元素指定方法的输入参数。
addSetNext(String pattern, String methodName, String paramType)
paramType为方法传入参数的类型
比如:
digester.addSetNext("database/user","addUser"),
这样在创建
database
及
user
实例之后,就会利用
database
的
addUser
方法把
user
实例注入.
5.
addCallMethod
(String pattern
,String methodName,int paraNumber)
该方法同样设置对象的属性,但更加灵活,不需要对象具有setter
根据pattern
规则指定的属性,调用对象的methodName方法,paraNumber参数是表示方法需要的参数个数,当paraNumber=0时,可以单独使用,不然需要配合addCallParam方法
比如:digester.addCallMethod("database/user/uerName","setUserName",0);
6.
addCallParam
(String pattern
,int paraIndex,String attributeName)
该方法与addCallMethod配合使用,根据rule指定的标签属性来调用方法
paraIndex表明需要填充的方法形参序号,从0开始,方法由addCallMethdo指定,attributeName指定标签属性名;
使用注意事项:
1.Digester类调用的顺序,必须与XML数据文件绝对一致;
2.Digester类依赖于JavaBean规范,类必须符合规范;
3.XML文件中标签/属性的名称必须与Bean中的一致(包括大小写);
六、Digester属性配置
org.apache.commons.digester3.Digester
实例对象包含若干成员属性,这些属性值是可以设置的,以便我们自定义解析操作;
为了让这些配置在XML解析前生效,这些属性值的更改一定要在
parse
方法调用之前设置;
如下是一些可以配置的属性
Property
|
Description
|
|