Apache Commons Digester

Digester是apache基金会的一个开源项目。最早运用于Struts中xml文件的解析,后来独立出来归到commons下面。它的主要开发人员是:Craig McClanahan。他开发了无数的OpenSource项目,包括大家都知道的Tomcat、Struts,同时他还是JSP和Servlet规范的制定成员之一。目前最新的Digester版本是3.2,发布于2011年12月份。该版本的使用依靠的Java环境最低版本为JDK1.5.,Digester依赖的组件:BeanUtils、Logging、Collections。

读者可以从http://commons.apache.org/网站上下载到,具体的下载网址是:http://commons.apache.org/digester/download_digester.cgi。作者从网站上下载的是commons-digester3-3.2-bin.zip。该压缩包包含了4个jar文件:
commons-digester3-3.2.jar :digester3的核心包,内部包含了digester3项目的类文件
commons-digester3-3.2-with-deps.jar:由于digester3还要依赖于其它组件,因此这个压缩包内是所有依赖的其它文件。
commons-digester3-3.2-javadoc.jar:digester3帮助文档
commons-digester3-3.2-sources.jar:digester3的Java源文件


处理规则

Rule类
处理规则(processing rule)指元素匹配模板用以识别什么时候采取行动,处理规则则用以定义行动的内容。从形式上讲,一个处理规则是一个java类,它扩展了org.apache.commons.digester3.Rule类。

这些事件方法会被触发:
1.public void begin(String namespace, String name, Attributes attributes):在一个匹配元素被识别出后的“开始”时刻被调用,这个元素的所有属性放在一个数据结构中被传递给begin()
2.public void body(String namespace, String name, String text)当元素的嵌套内容(如子元素)被识别出时被调用。在解析的过程中,前后的空白被去掉了。
3.public void end(String namespace, String name) throws Exception :匹配元素的“结束”时刻被调用。如果子元素也匹配相关的规则,则这些规则的方法需都执行毕,才能达到该元素的“结束”时刻。
4.fpublic void finish() throws Exception:解析结束时被调用,以提供给各个规则以清理临时数据的机会。


Digester类

使用Digester解析XML文档的基本步骤如下:        
创建Digester对象实例。        
设置该Digester对象的配置属性(可选)。        
将需要的初始对象push到该Digester对象的对象栈上(可选)。        
需要注册所有的XML元素匹配模式与处理规则之间的映射关系。        
用digester.parse()解析的XML文档对象,得到目标对象。

 

Digester提供的常见处理规则


Apache Commons Digester_第1张图片
 
 

Formally, a processing rule is a Java class that subclasses the org.apache.commons.digester3.Rule interface. Each Rule implements one or more of the following event methods that are called at well-defined times when the matching patterns corresponding to this rule trigger it:

  • begin() - Called when the beginning of the matched XML element is encountered. A data structure containing all of the attributes corresponding to this element are passed as well.
  • body() - Called when nested content (that is not itself XML elements) of the matched element is encountered. Any leading or trailing whitespace will have been removed as part of the parsing process.
  • end() - Called when the ending of the matched XML element is encountered. If nested XML elements that matched other processing rules was included in the body of this element, the appropriate processing rules for the matched rules will have already been completed before this method is called.
  • finish() - Called when the parse has been completed, to give each rule a chance to clean up any temporary data they might have created and cached.

As you are configuring your digester, you can call the addRule() method to register a specific element matching pattern, along with an instance of a Rule class that will have its event handling methods called at the appropriate times, as described above. This mechanism allows you to create Rule implementation classes dynamically, to implement any desired application specific functionality.

In addition, a set of processing rule implementation classes are provided, which deal with many common programming scenarios. These classes include the following:

  • ObjectCreateRule - When the begin() method is called, this rule instantiates a new instance of a specified Java class, and pushes it on the stack. The class name to be used is defaulted according to a parameter passed to this rule's constructor, but can optionally be overridden by a classname passed via the specified attribute to the XML element being processed. When the end() method is called, the top object on the stack (presumably, the one we added in the begin() method) will be popped, and any reference to it (within the Digester) will be discarded.
  • FactoryCreateRule - A variation of ObjectCreateRule that is useful when the Java class with which you wish to create an object instance does not have a no-arguments constructor, or where you wish to perform other setup processing before the object is handed over to the Digester.
  • SetPropertiesRule - When the begin() method is called, the digester uses the standard Java Reflection API to identify any JavaBeans property setter methods (on the object at the top of the digester's stack) who have property names that match the attributes specified on this XML element, and then call them individually, passing the corresponding attribute values. These natural mappings can be overridden. This allows (for example) a class attribute to be mapped correctly. It is recommended that this feature should not be overused - in most cases, it's better to use the standard BeanInfo mechanism. A very common idiom is to define an object create rule, followed by a set properties rule, with the same element matching pattern. This causes the creation of a new Java object, followed by "configuration" of that object's properties based on the attributes of the same XML element that created this object.
  • SetPropertyRule - When the begin() method is called, the digester calls a specified property setter (where the property itself is named by an attribute) with a specified value (where the value is named by another attribute), on the object at the top of the digester's stack. This is useful when your XML file conforms to a particular DTD, and you wish to configure a particular property that does not have a corresponding attribute in the DTD.
  • SetNextRule - When the end() method is called, the digester analyzes the next-to-top element on the stack, looking for a property setter method for a specified property. It then calls this method, passing the object at the top of the stack as an argument. This rule is commonly used to establish one-to-many relationships between the two objects, with the method name commonly being something like "addChild".
  • SetTopRule - When the end() method is called, the digester analyzes the top element on the stack, looking for a property setter method for a specified property. It then calls this method, passing the next-to-top object on the stack as an argument. This rule would be used as an alternative to a SetNextRule, with a typical method name "setParent", if the API supported by your object classes prefers this approach.
  • CallMethodRule - This rule sets up a method call to a named method of the top object on the digester's stack, which will actually take place when the end() method is called. You configure this rule by specifying the name of the method to be called, the number of arguments it takes, and (optionally) the Java class name(s) defining the type(s) of the method's arguments. The actual parameter values, if any, will typically be accumulated from the body content of nested elements within the element that triggered this rule, using the CallParamRule discussed next.
  • CallParamRule - This rule identifies the source of a particular numbered (zero-relative) parameter for a CallMethodRule within which we are nested. You can specify that the parameter value be taken from a particular named attribute, or from the nested body content of this element.
  • NodeCreateRule - A specialized rule that converts part of the tree into a DOM Node and then pushes it onto the stack.

 基本上来说,Digester和SAX解析xml的过程很像,它的原理就是制定一些规则,在遍历每个节点时检查是否有匹配的规则,如果有就执行对应的操 作。例如,上面的代码中,“digester.addObjectCreate("charts/chart", ChartConfig.class);”这一句的作用是告诉Digester:如果遇到匹配“charts/chart”形式的节点,就执行一个“对象 创建”操作,创建什么对象呢,应该创建Class为“ChartConfig.class”的对象;类似的,addSetProperties()是告诉 Digester将指定节点的属性全部映射到对象的属性,在这个例子里指的就是id属性;addBeanPropertySetter()是将子节点转换 为对象的属性,这个方法还可以有第二个参数,当对象的属性名和子节点的名字不一样时用来指定对象的属性名;addSetNext()是说在遇到匹配节点 后,对当前对象的父对象执行一个方法,参数是当前参数


        addObjectCreate(String pattern, String className, String attributeName)
         pattern--匹配的节点
         className--该节点对应的默认实体类
         attributeName--如果该节点有className属性,用className的值替换默认实体类       
        
       //将指定节点的属性映射到对象,即将School节点的name的属性映射到School.java 
       addSetProperties
       
       addSetNext(String pattern, String methodName, String paramType)
        pattern--匹配的节点
        methodName--调用父节点的方法
        paramType--父节点的方法接收的参数类型
      
         
        //为Connector节点创建规则 
        digester.addRule("Server/Service/Connector", 
                         new ConnectorCreateRule());         
        如果某个节点包含的规则比较多,可以为该节点创建一个规则类
        执行digester.addRuleSet(new EngineRuleSet("Server/Service/")) 
        可以将EngineRuleSet内包含的规则,添加到当前digester中
         
       
        //使用方式一,调用Digester中的方法解析XPATH,
        // 遇到members元素节点开始时,构造Members类的对象 
        digester.addObjectCreate("members", Members.class); 
         
        // 遇到members元素的子元素member开始时,构造Member类的对象 
        digester.addObjectCreate("members/member", Member.class); 
         
        // set up members元素的子元素member的属性值, 前提是xml中的属性名必须与java bean中的一致 
        // 并且java bean 要有对应的setter方法 
        digester.addSetProperties("members/member"); 
         
        // 将当前members元素的子元素member所对应的bean 通过调用其parent members所对应的Members实例 
        // 中的方法 addMember,并以其所对应的bean作为参数传入,这样就可以在Members中初始化member的实例了 
        digester.addSetNext("members/member", "addMember"); 
         
        // 遇到members元素的子元素member中的skill节点时调用其直接parent member实例中的addSkill方法 
        // 第三个参数为xml的参数索引,这里 0 表示去取skill元素body内的值,并且取出的只能是String类型(假如是数字,而addSkill中的参数为int类型,这样会抛No such accessible method exception, 
        // 就是说默认只认识String类型的参数,改成String类型参数就能取到,看下面的level就知道) 
        digester.addCallMethod("members/member/skill", "addSkill", 0); 
         
        // 当需要参入不同类型的多个参数时,这样用 
        digester.addCallMethod("members/member/equipment", "addEquipment", 3,  
                new String[]{"java.lang.String", "java.lang.Integer", "java.lang.String"}); 
        // 标记equipment 元素 body中的值为参数一 
        digester.addCallParam("members/member/equipment", 0); 
        // 标记equipment 元素 属性id的值为参数二 
        digester.addCallParam("members/member/equipment", 1, "id"); 
        // 标记equipment 元素 属性version的值为参数三 
        digester.addCallParam("members/member/equipment", 2, "version"); 
         
        // 抛No such accessible method: setLevel() on object: org.oham.xml.Member,setLevel中传入的是int类型参数,它不认 
        //digester.addCallMethod("members/member/level", "setLevel", 0); 
         
        //解决1:调用CallParam标记参数 
        digester.addCallMethod("members/member/level", "setLevel", 1,  
                                            new String[]{"java.lang.Integer"}); 
        digester.addCallParam("members/member/level", 0); 
         
        //解决2:调用addBeanPropertySetter,去call bean中相应的serter方法 
        //digester.addBeanPropertySetter("members/member/level","level");

 

// 使用方式二,将XPATH写到另一个xml封装起来,使用FromXmlRulesModule这个类读入xml并用其生成digester实例 
        loadXMLRules(MembersParser.class.getClass().getResource("/org/oham/xml/test-members-rules.xml"));
         // 使用RulesModule生成digester实例 
        Digester digester = DigesterLoader.newLoader(new RulesModule()).newDigester(); 
        return digester.parse(xmlFile);

 

    <?xml version="1.0"?> 
    <!DOCTYPE digester-rules PUBLIC 
      "-//Apache Commons //DTD digester-rules XML V1.0//EN" 
      "http://commons.apache.org/digester/dtds/digester-rules-3.0.dtd"> 
       
    <digester-rules> 
     
        <pattern value="members"> 
            <!-- 对应digester.addObjectCreate --> 
            <object-create-rule classname="org.oham.xml.Members" /> 
             
            <pattern value="member"> 
                <object-create-rule classname="org.oham.xml.Member" /> 
                 
                <!-- 对应digester.addSetProperties --> 
                <set-properties-rule /> 
                 
                <!-- 对应digester.addSetNext --> 
                <set-next-rule methodname="addMember" paramtype="org.oham.xml.Member"/> 
                 
                <!-- 对应digester.addCallMethod --> 
                <call-method-rule pattern="skill" methodname="addSkill" paramcount="0" /> 
                 
                <pattern value="equipment"> 
                    <call-method-rule methodname="addEquipment" paramcount="3" paramtypes="java.lang.String,java.lang.Integer,java.lang.String" /> 
                     
                    <!-- 对应digester.addCallParam --> 
                    <call-param-rule paramnumber="0" /> 
                    <call-param-rule paramnumber="1" attrname="id" /> 
                    <call-param-rule paramnumber="2" attrname="version" /> 
                     
                </pattern> 
                 
                <pattern value="level"> 
                    <call-method-rule methodname="setLevel" paramcount="1" paramtypes="java.lang.Integer" /> 
                    <call-param-rule paramnumber="0" /> 
                     
                    <!-- 对应digester.addBeanPropertySetter  --> 
                    <!-- <bean-property-setter-rule propertyname="level" /> --> 
                </pattern> 
                 
            </pattern> 
        </pattern> 
         
    </digester-rules>

 

 addObjectCreate( String pattern, Class<?> clazz )

addBeanPropertySetter( String pattern )

addSetProperties( String pattern, String attributeName, String propertyName )

addSetNext( String pattern, String methodName )

<T> T parse( File file )

// 设置对XML文档资料是否进行DTD验证  
digester.setValidating(false);

 

 InputStream inputXML = new BufferedInputStream(
                XLSReaderTest.class.getResourceAsStream("departments.xml"));
        InputStream xsd = new BufferedInputStream(
                XLSReaderTest.class.getResourceAsStream("xls_template.xsd"));
        // 查找支持指定模式语言的 SchemaFactory 的实现并返回它
        SchemaFactory factory = SchemaFactory
                .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);

        // 构造Schema Source
        Source xsdSource = new StreamSource(xsd);
        // 解析作为模式的指定源并以模式形式返回它
        Schema schema = factory.newSchema(xsdSource);

        // 根据Schema检查xml文档的处理器,创建此 Schema 的新 Validator
        Validator validator = schema.newValidator();

        // 构造待验证xml Source
        Source xmlSource = new StreamSource(inputXML);

        // 执行验证
        //validator.setErrorHandler(new DefaultErrorHandler(true));
        validator.validate(xmlSource);
       


分类

方法名

含义

对象创建

 

objectCreateRule

这个规则类实例化一个指定的java类,并将其压入栈顶。这个被实例化的类的名字,默认为这个规则类构造函数得到的参数,也可以通过指定正在处理的xml元素的属性来传递一个新的类的名字。当end()方法被调用时,栈顶的对象被弹出,Digester中对它的任何引用将被忽略。

factoryCreateRule

创建Java对象的另一种选择。当待创建的Java对象没有无参构造函数,或需要在创建时需要进行额外的设置时,需要用此方法。

属性设置

 

setPropertiesRule

begin()方法被调用时, Digester使用标准的Java反射API,将栈顶对象的属性设置为XML元素的同名属性值。

setPropertyRule

begin()方法被调用时, Digester调用栈顶对象来指定属性的设置方法,设置其值。

父子关系管理

 

setNextRule

end()方法被调用时,Digester分析第二栈顶元素,寻找一个特定属性(property)的设置方法(setter method),并接着调用这个方法,以栈顶的元素作参数。这个规则通常用来在两个对象间建立1对多的关系。

setTopRule

end()方法被调用时,Digester分析栈顶元素,寻找一个特定属性(property)的设置方法(setter method),并接着调用这个方法,以第二栈顶的元素作参数。这个规则通常用来在两个对象间建立1对多的关系。

任意方法调用

 

callMethodRule

end()方法被调用时, Digester将调用栈顶元素指定名称的方法。除了方法名外,此rule还需要配置参数数目,参数类型。参数值一般通过CallParamRule得到。

callParamRule

rule内嵌于CallParamRule中,按顺序(相对于0)定义了CallParamRule中参数值的来源,可选的来源包括当前XML元素的属性或内容。

其它

 

nodeCreateRule

XML文件树的一部分转换为DOM节点,并pushDigester的对象栈上。

 

你可能感兴趣的:(apache,commons)