Digester解析XML文件

 
这是我的第一篇博客,基本都是从多个博客中借鉴过来,然后按照自己的理解整理了一下写的,第一次写博客不知道该注意什么,有不好的地方请指出,非常感谢
一、前言
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有两种使用方式:
  1. 一种为tomat内嵌的org.apache.tomcat.util.digester.Digester;
  2. 另一种为digester maven依赖。
本文采用第二种--maven依赖的方式。
 
<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-digester3</artifactId>
  <version>3.2</version>
</dependency>
 
三、 digester的使用规则
1、Digester 解析过程 分为两步
  1. 定义好模式(定义要匹配的标签)
  2. 将模式与规则(定义匹配到标签后的行为的对象)相关联
2、模式 规则  是什么
    模式:
        说白了就是xml文件的元素标签,只不过是附带了父节点的标签, 父元素的模式+”/”+子元素的模式 拼接而成
     规则:
        rule,当遇到一个模式(xml标签元素)时,需要执行相应的 一个或多个动作。简单来说 就是定义当模式匹配成功时,程序需要做什么。
        规则是 org.apache.commons.digester.Rule 类的实例

注意: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对象执行的操作:
  1. Digester对象首先会先遇到 employee元素的开始标签,然后 Digester对象 会检查  是否有规则和模式employee相关联,若有 Digester会执行相应Rule对象的begin方法,若有多个Rule对象与该模式匹配,则按照其添加到Digester对象的顺序逐个执行;
  2. 然后 它会 遇到office元素的开始标签,Digester对象会检查是否有规则与模式  employee/office相关联,若有,则执行Rule的begin()方法,
  3. 接下来Digester会遇到address标签的开始标签,它会检查是否有规则与模式employee/office/address相关联,若有则执行它的 begin()方法。
  4. 接着,Digester对象会遇到 address元素的结束标签,会执行相匹配的Rule的end()方法。
  5. 再下来,Digester对象会遇到office元素的的结束标签,会执行相匹配的Rule对象的end()方法
  6. 最后,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;
        this .namespaceURI = " http://www.mycompany.com/MyNamespace " ;
    }
 
    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;
 
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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值