注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

骇客归来

ぁ枫あ

 
 
 

日志

 
 

Apache之Digester (1)  

2007-11-28 17:34:39|  分类: Digester |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
Digester是apache开源项目Commons中的一个子项目,是一款解析处理XML文档的工具。现在Java领域中流传了很多有关处理XML文 档解析的工具,除官方(Sun)的标准的SAX(最新版本2.0),DOM(最新版本3.0,在Tiger版本中集成)外[JAXP只是Sun定义的一组 规范接口],其他开源不泛多多,比如Jdom,Dom4j,Castor等等,包括这款Apache的digester。说到这里,你不得不佩服开源组织 的强大智慧的结晶,digester处理XML文档基于XML节点树Path的规则,实在给人一种赏心悦目之感,这也是偶一直对其情有独钟的最大理由。废 话免了,转入正题。
   刚说到Digester处理是基本类似于XML文档树节点遍历的规则来进行处理,底层处理是采用了SAX,基于事件驱动的模式。举个例子:
   <Company>
     <Technology>
       <name length="4">Corx</name>
       <date>2005.06.27</date>
     </Technology>
    
     <Product>
       <name length="4">Kxcp</name>
       <date>2004.12.29</date>
     </Product>
   </Company>
  
   在digester中,定义了一些规则(rule),对遍历的节点path预先对应好要处理的规则,即当解析器遍历到某个节点的时候,如果发现当前节点有对应的处理规则,调用相应的rule进行处理。举个例子:
   Company/Technology -> ObjectCreatedRule //对象创建规则
   Company/Technology/name -> BeanPropertySetterRule //属性存取规则
   ...
  
   对以上的解释可能还不太明白,不要着急,下面详细解释一下digester的基本原理,喝杯咖啡,慢慢来~
  
   首先看看org.apache.commons.digester.Digester这个类,查看source发现Digester本身继承了 DefaultHandler句柄,DefaultHandler句柄是SAX中基于时间驱动的缺省的句柄实现(包含ContentHandler, ErrorHandler, EntityResolver, DTDHandler),这个句柄不用多介绍了吧,相信用过SAX的哥们都明白。:)。刚刚不是说到了Rule了嘛,digester中定义了一个规则处 理接口org.apache.commons.digester.Rule,此接口类似于ContentHandler接口中的方法,稍稍有点不同,主要 有begin(), body(), end(), finish()方法。而digester缺省定义了许多有效的常用规则,每个规则都实现这个接口, 如果没有什么特殊需求,一般这些规则是够用了,罗列一下:BeanPropertySetterRule, CallMethodRule, CallParamRule, FactoryCreateRule, NodeCreateRule, ObjectCreateRule, ObjectParamRule,PathCallParamRule, SetNestedPropertiesRule, SetNextRule, SetPropertiesRule, SetPropertyRule, SetRootRule, SetTopRule,这些规则的意思稍后说。同时,对这些规则,digester还定义了一个规则的容器接口Rules(抽象类),这个抽象类接口容器 容纳规则,并定义了规则匹配的模式,digester实现了一个基本的匹配模式RulesBase,简要看看这个实现中的两个最重要的方法:
   .....
   public void add(String pattern, Rule rule) {
         // to help users who accidently add '/' to the end of their patterns
         int patternLength = pattern.length();
         if (patternLength>1 && pattern.endsWith("/") {
             pattern = pattern.substring(0, patternLength-1);
         }
        
        
         List list = (List) cache.get(pattern);
         if (list == null) {
             list = new ArrayList();
             cache.put(pattern, list);
         }
         list.add(rule);
         rules.add(rule);
         if (this.digester != null) {
             rule.setDigester(this.digester);
         }
         if (this.namespaceURI != null) {
             rule.setNamespaceURI(this.namespaceURI);
         }

     }

还有一个方法:
   ...
   public List match(String namespaceURI, String pattern) {

         // List rulesList = (List) this.cache.get(pattern);
         List rulesList = lookup(namespaceURI, pattern);
         if ((rulesList == null) || (rulesList.size() < 1)) {
             // Find the longest key, ie more discriminant
             String longKey = "";
             Iterator keys = this.cache.keySet().iterator();
             while (keys.hasNext()) {
                 String key = (String) keys.next();
                 if (key.startsWith("*/") {
                     if (pattern.equals(key.substring(2)) ||
                         pattern.endsWith(key.substring(1))) {
                         if (key.length() > longKey.length()) {
                             // rulesList = (List) this.cache.get(key);
                             rulesList = lookup(namespaceURI, key);
                             longKey = key;
                         }
                     }
                 }
             }
         }
         if (rulesList == null) {
             rulesList = new ArrayList();
         }
         return (rulesList);
     }
     ...
    
     以上基本实现只是digester默认匹配规则,如果你要更换自己的规则匹配模式,则只需要继承 org.apache.commons.digester.Rules接口,定义自己的匹配方式,digester同时还给我们提供了一个比较复杂,不过 非常常用的匹配模式,那就是通配符匹配模式,引入了”!“、”*“、”?“三个符号进行通配的匹配模式,这个类就是 org.apache.commons.digester.ExtendsBaseRules,后续再说。
    
     digester就是通过以上的几种接口组件,同时配合操作数栈,进行XML解析。具体说,就是在parse XML文档之前,预先向容器集合(默认就是RulesBase容器)对XML文档中的节点path注入匹配规则,然后在parse文档的时候,遭遇到节点 时时,调用SAX句柄中相应的方法,配合操作数栈,根据定义好的匹配模式,调用相应规则中的方法,将XML序列化成Java Object。介绍有点抽象,沿用digester本身带的例子介绍一下:
     ...
     //对如下的XML文档
     <address-book>
       <person id="1" category="acquaintance">
         <name>Gonzo</name>
         <email type="business">gonzo@muppets.com</email>
       </person>
       <person id="2" category="rolemodel">
         <name>Kermit</name>
         <email type="business">kermit@muppets.com</email>
         <email type="home">kermie@acme.com</email>
       </person>
     </address-book>
     ...
...
    
     Digester digester = new Digester();
    
     AddressBook book = new AddressBook();
     d.push(book); //将AddressBook实例压入堆栈
    
     digester.addObjectCreate("address-book/person", Person.class);//对person节点注入对象创建规则,即在SAX的事件遭遇到person节点的时候,创建Person类的实例,并压 入堆栈,此时堆栈中从栈顶到栈底分别为AddressBook实例,Person类实例。
     digester.addSetProperties("address-book/person";// 对person节点注入属性设置规则,即在SAX的事件遭遇到person节点中的Attributes时,根据属性列表中的属性值对,这儿就是id= "1", category="acquaintance",使用Java反射(reflection)机制,调用当前栈顶对象即Person实例类中id、 category属性的标准的JavaBean方法,setId, setCategory。
    
     digester.addSetNext("address-book/person", "addPerson";// 对person节点注入父节点方法调用规则,即在SAX事件遭遇到person节点的时候,调用栈中Person实例的父实例中的addPerson方 法。d.addCallMethod("address-book/person/name", "setName", 0);//对name节点注入方法调用规则,调用当前栈顶对象即Person实例中的setName方法,而此方法的参数即是当前name节点的字符内 容。通常这个规则和addCallParam规则配合使用,这儿是一种特殊情况。
     digester.addCallMethod("address-book/person/email", "addEmail", 2);//对email节点注入方法调用规则,调用当前栈顶对象即Person实例中的addEmail方法,此方法需要两个参数,一个是从属性值的 type属性获取,一个是从email本身的字符内容获取。
     digester.addCallParam("address-book/person/email", 0, "type";//对email节点注入参数调用规则,将当前节点的type属性值压入方法操作数栈
     digester.addCallParam("address-book/person/email", 1);//对email节点注入参数调用规则,将当前节点的字符属性值压入方法操作数栈。
    
     System.out.println(book);//打印book中值。。
     ...
    
     通过以上注释应该不难理解吧。
    
     下面再对以上所说的几种常用规则作一个详细的介绍:
     ObjectCreateRule:这个规则比较简单,此规则就是对指定的模式创建一个类的实例,并将当前实例压入堆栈,并且在遭遇元素结束
     时,将当前的栈顶实例弹出栈。
     对应Digester中有关这个规则的Javadoc方法说明:
       addObjectCreate(java.lang.String pattern, java.lang.Class clazz) - 方法参数说明了一切
       addObjectCreate(java.lang.String pattern, java.lang.String className) - 同上
       addObjectCreate(java.lang.String pattern, java.lang.String attributeName, java.lang.Class clazz) - 这个稍微解释一下,
       多了一个参数attributeName,这个参数的意思就是如果在当前匹配模式的节点中定义了属性,则默认就采用这个attributeName所
       对应的值来加载实例。比如以上面的例子加入person元素还有一个属性, class="test.org.apache.commons.digester.Person1",
       则此规则会加载Person1实例而不是Person实例。明白?!
       addObjectCreate(java.lang.String pattern, java.lang.String className, java.lang.String attributeName) -同上
      
     FactoryCreateRule:这个规则是基于工厂模式创建指定模式的一个类的实例。跟ObjectCreateRule类似,不同的是其参数Class继承了
     ObjectCreationFactory接口。此接口中有个方法createObject(Attributes attrs),创建类的实例,在规则中将此类的实例压入堆栈。
     对应Digester中有关这个规则的Javadoc方法说明:
       addFactoryCreate(java.lang.String pattern, java.lang.Class clazz) - 一目了然,不用说了。只是clazz必须是实现了
       ObjectCreationFactory接口的类。
       addFactoryCreate(java.lang.String pattern, java.lang.Class clazz, boolean ignoreCreateExceptions) - 同上,多了一个参
       数,ignoreCreateExceptions表明是否忽略在创建类的过程中忽略抛出的exception。
       addFactoryCreate(java.lang.String pattern, java.lang.Class clazz, java.lang.String attributeName) - 稍微介绍一下这里
       的attributeName参数,这个参数跟ObjectCreationRule规则中的attributeName雷同,不同的是这个属性的值必须是实现了接口
       ObjectCreationFactory接口的类。
       addFactoryCreate(java.lang.String pattern, java.lang.Class clazz, java.lang.String attributeName, boolean ignoreCreateExceptions)
       - 同上
       addFactoryCreate(java.lang.String pattern, ObjectCreationFactory creationFactory) - 同上
       addFactoryCreate(java.lang.String pattern, ObjectCreationFactory creationFactory, boolean ignoreCreateExceptions) - 同上
       addFactoryCreate(java.lang.String pattern, java.lang.String className) - 同上
       addFactoryCreate(java.lang.String pattern, java.lang.String className, boolean ignoreCreateExceptions) - 同上
       addFactoryCreate(java.lang.String pattern, java.lang.String className, java.lang.String attributeName) - 同上
       addFactoryCreate(java.lang.String pattern, java.lang.String className, java.lang.String attributeName, boolean ignoreCreateExceptions)

  评论这张
 
阅读(161)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017