Tomcat中xml的解析器Digester 第二篇(共三篇)

来源:互联网 发布:信捷plc模拟量编程实例 编辑:程序博客网 时间:2024/05/22 00:54

转自:http://alanwu.iteye.com/blog/143911

 为了方便这篇文章仍然使用第一篇的XML和Bean。 第一篇实现了SaxCatalogUnmarshaller, 利用SAX技术将XML转成一个装配好的Java Object. 但是其中有很多需要改进的地方。 最明显需要改进的就是有大量的if-else来匹配刚读进来的XML元素, 如果XML中大量不同的类对应, 将会有更多的if-else而且不可重用。 对于大量if-else, 策略模式是一个很好的选择。 

     apache 的 Digester正是利用了策略模式来解决这个问题, 当SAX产生startElement, endElement等事件的时候, 马上将事件分配给匹配的Rule。  客户端只需要注册不同的模式和它们的对应关系,剩下来的事情转发给各不同的Rule实现。 
 

    Digester最开始使用的是Struts, 使用后发现非常好且通用. Digester被提到commons.apache.org. 


apache Digester中 实现的Rule:ObjectCreateRule.begin代码: 

Java代码  收藏代码
  1. /** 
  2.   * Process the beginning of this element. 
  3.   * 
  4.   * @param attributes The attribute list of this element 
  5.   */  
  6.  public void begin(Attributes attributes) throws Exception {  
  7.      // 识别类名  
  8.      // Identify the name of the class to instantiate  
  9.      String realClassName = className;  
  10.      if (attributeName != null) {  
  11.          String value = attributes.getValue(attributeName);  
  12.          if (value != null) {  
  13.              realClassName = value;  
  14.          }  
  15.      }  
  16.      if (digester.log.isDebugEnabled()) {  
  17.          digester.log.debug("[ObjectCreateRule]{" + digester.match +  
  18.                  "}New " + realClassName);  
  19.      }  
  20.      // 实现类并将实例放到堆栈中  
  21.      // Instantiate the new object and push it on the context stack  
  22.      Class clazz = digester.getClassLoader().loadClass(realClassName);  
  23.      Object instance = clazz.newInstance();  
  24.      digester.push(instance);  
  25.   
  26.  }  


end代码 

Java代码  收藏代码
  1. /** 
  2.  * Process the end of this element. 
  3.  */  
  4. public void end() throws Exception {  
  5.   
  6.     Object top = digester.pop();  
  7.     if (digester.log.isDebugEnabled()) {  
  8.         digester.log.debug("[ObjectCreateRule]{" + digester.match +  
  9.                 "} Pop " + top.getClass().getName());  
  10.     }  
  11.   
  12. }  


上面start和end代码, 和SaxCatalogUnmarshaller比较可以看出, 对XML元素的对比,类实现和对内容堆栈的处理都封装出来了,客户端无需关注这些技术细节。 

客户端只需要将不同的模式和不同的Rule对应的注册到Digester里,分发和实现就可以交给Digester和不同的Rule做了。 

DigesterDriver.java: 

Java代码  收藏代码
  1. package benewu.gmail.study.tomcat.digester;  
  2.   
  3. import java.io.File;  
  4. import java.net.URL;  
  5.   
  6. import org.apache.commons.digester.Digester;  
  7.   
  8.    
  9.   
  10. public class DigesterDriver {  
  11.   
  12.    public static void main( String[] args ) {  
  13.   
  14.       try {  
  15.          Digester digester = new Digester();  
  16.          digester.setValidating( false );  
  17.      
  18.          //The patterns must match XML elements, based on their name and location in the document tree.   
  19.          //The syntax used to describe the matching patterns resembles the XPath match patterns, a little:   
  20.          //the pattern catalog matches the top-level <catalog> element,  
  21.          //the pattern catalog/book matches a <book> element nested directly inside a <catalog> element  
  22.            
  23.          /*ObjectCreateRule: 利用默认构造函数创建类实例并且压到堆栈, 
  24.           *元素结束的时候会从堆栈pop出来.  
  25.           */  
  26.          digester.addObjectCreate( "catalog", Catalog.class );  
  27.          digester.addObjectCreate( "catalog/book", Book.class );  
  28.            
  29.          /* 
  30.           * BeanPropertySetterRule: 将名字属性赋值给栈顶的元素 
  31.           * (Example: <page>10</page>.) 
  32.           */  
  33.          digester.addBeanPropertySetter( "catalog/book/author""author" );  
  34.          digester.addBeanPropertySetter( "catalog/book/title""title" );  
  35.            
  36.          /* 
  37.           * SetNextRule: pop栈顶实例并且利用定义的方法传递给下个对象实例, 通常用来将一个完整的bean插到父对象上. 
  38.           */  
  39.          digester.addSetNext( "catalog/book""addBook" );  
  40.   
  41.          digester.addObjectCreate( "catalog/magazine", Magazine.class );  
  42.          digester.addBeanPropertySetter( "catalog/magazine/name""name" );  
  43.   
  44.          digester.addObjectCreate( "catalog/magazine/article", Article.class );  
  45.            
  46.          /* 
  47.           * SetPropertiesRule: 将名字属性的值赋给栈顶对象. 
  48.           * (Typically used to handle XML constructs like <article page="10">.) 
  49.           */  
  50.          digester.addSetProperties( "catalog/magazine/article""page""page" );  
  51.          digester.addBeanPropertySetter( "catalog/magazine/article/headline" );   
  52.          digester.addSetNext( "catalog/magazine/article""addArticle" );  
  53.   
  54.          digester.addSetNext( "catalog/magazine""addMagazine" );  
  55.            
  56.          URL fileURL = DigesterDriver.class.getResource("catalog.xml");  
  57.          File input = new File(fileURL.getFile());  
  58.          Catalog c = (Catalog)digester.parse( input );  
  59.   
  60.          System.out.println( c.toString() );  
  61.   
  62.       } catch( Exception exc ) {  
  63.          exc.printStackTrace();  
  64.       }  
  65.    }  
  66. }  


DigesterDriver 实现了和SaxCatalogUnmarshaller完全相同的功能, 但更加灵活和可扩展。 

这里使用的Rule有: 
ObjectCreateRule, SetPropertiesRule, BeanPropertySetterRule, SetNextRule, 在代码中已经做了注释。 


下节我将分析Tomcat中使用到和自己实现的部分Rule, 和典型应用。 


参考: 
1 The Hidden Gems of Jakarta Commons 
http://www.onjava.com/pub/a/onjava/2004/12/22/jakarta-gems-1.html?page=2 

2 Parsing, indexing, and searching XML with Digester and Lucene 
http://www.ibm.com/developerworks/java/library/j-lucene/ 

3 Learning and Using Jakarta Digester 
http://www.onjava.com/pub/a/onjava/2002/10/23/digester.html?page=1

原创粉丝点击