设为首页 收藏本站
查看: 607|回复: 0

[经验分享] Apache Commons Digester

[复制链接]

尚未签到

发表于 2016-12-30 10:01:22 | 显示全部楼层 |阅读模式
  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提供的常见处理规则


DSC0000.jpg
 
   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的对象栈上。
 

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-321462-1-1.html 上篇帖子: Apache之Digester 下篇帖子: tomcat和apache整合
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表