美文网首页
Tomcat相关技术-Digester(二)Digester使用

Tomcat相关技术-Digester(二)Digester使用

作者: 贪睡的企鹅 | 来源:发表于2019-08-05 21:56 被阅读0次

    1 概述

    • Digester是一款用于将xml转换为Java对象的事件驱动型工具,是对SAX的高层次的封装。Digester相对于SAX提供了更加友好的接口,隐藏了xml节点具体层次的细节,让开发者能加载专注于处理过程。

    • Digester最早是Web框架Apache Struts的一部分,后来由于其通用性移植到了Apache Common项目中。

    2 Digester解决了SAX哪些问题

    SAX基于事件解析Xml,最重要的就是要编写一个解析器类。

    public class SaxHandler extends DefaultHandler {
    
         /**
         * 解析一个xml标签字符时触发回调
           (该触发回调发生在startElement之后endElement之前)
         * @param ch  xml文档完整字符数组
         * @param start   当前标签中字符在ch开始位置
         * @param length  当前标签中字符的长度
         * @throws SAXException
         */
        @Override
        public void characters(char[] ch, int start, int length){
            ..省略实现
        }
        
        
         /**
         * 解析一个xml标签结束时触发回调
         * @param uri
         * @param localName
         * @param name        当前标签的名称
         * @throws SAXException
         */
        @Override
        public void endElement(String uri, String localName, String name){
            ..省略实现
        }
        
        
        /**
         * 解析一个xml标签开始时触发回调
         * @param uri
         * @param localName
         * @param name        当前标签的名称
         * @param attributes  标签中的属性对象
         * @throws SAXException
         */
        @Override
        public void startElement(String uri, String localName, String name,
                                 Attributes attributes) throws SAXException {
            ..省略实现
        }
                                 
        /**
         * 解析一个xml文件开始时回调
         */
        @Override
        public void startDocument() throws SAXException{
            ..省略实现
        }
    
        /**
         * 解析一个xml文件结束时回调
         */
        @Override
        public void endDocument() throws SAXException{
            ..省略实现
        }
    

    2.1 SAX缺陷

    • 1 如果解析XML上不同标签节点存在依赖关系时,需要开发者自行维护依赖关系,说具体就是如果需要子标签对象手动设置到父标签属性中,子标签需要程序开发者手动保存下来。

    • 2 不同xml的标签属性,字符都不同,而SAX只提供了所有标签通用回调事件,不能针对不同标签定制。

    3 Digester设计

    image
    • 1 Digester继承DefaultHandler表明Digester是对SAX的扩展实现

    • 2 Digester内部存类型为Rules的属性,Rules为了一个其实现类为RulesBase,RulesBase内部维护HashMap,其中key对应匹配xml规则的字符串,value表示表示针对此xml规则解析规则列表。每个解析规则使用Rule类来表示。

    public class Digester extends DefaultHandler2 {
           ...省略代码
           protected Rules rules = null;
           ...省略代码
    }
    
    public class RulesBase implements Rules {
        ...省略代码
        //String     表示匹配xml匹配规则(可以用正则表达式)
        //List<Rule> 表示针对对应xml规则解析规则列表
        protected HashMap<String,List<Rule>> cache = new HashMap<>();
        ...省略代码
    
    
    • 3 同时Digester内部维护了一个栈数据结构,用来处理当前解析的xml标签节点,解析前会将xml标签对象入栈(push),解析后会将xml标签对象出栈(pop),栈最顶部的对象永远都是现在正在解析的对象。这样就可以将有父子关系的节点对象在栈中保存下来。

    4 Rule规则对应接口方法

     begin():当读取到匹配节点的开始部分时调用,会将该节点的所有属性作为从参数传入。
    
     body():当读取到匹配节点的内容时调用,注意指的不是子节点,而是嵌入内容为普通文本。
    
     end():当读取到匹配节点的结束部分时调用,如果存在子节点,只有当子节点处理完毕后该方法才会被调用。
    
     finish():当整个parse()方法完成时调用,多用于清楚临时数据和缓存数据
    

    可以发现这和DefaultHandler方式很像,不同的时规则只针对特定的某个xml标签规则

    5 xml匹配规则

    [图片上传失败...(image-4163f4-1565013353761)]

    例子

      <a>            
        <b>          
          <c></c>    
        </b>
        <b>
          <c></c>
          <c></c>
          <c></c>
        </b>
      </a>  
      
    a匹配<a>标签 
    a/b匹配<a><b>
    a/b/c匹配<a><b><c>
    */b 匹配<a><b>
    

    6 Digester常用API

    public void setValidating(boolean validating) // 是否根据DTD校验XML
    
    public void push(Object object) // 将对象压入栈
    
    public Object peek() // 获取栈顶对象
    
    public Object pop() // 弹出栈顶对象
    
    public Object parse(InputSource input) // 解析输入源
    
    public void addRule(String pattern, Rule rule) //针对指定xml标签设置规则解析器
    
    
    

    7 给指定标签设置规则

    1 创建一个定义规则类,该类需要继承Rule

    2 调用digester.addRule API 函数

    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
        }
    }
    
    //表示匹配到<Server><Service><Connector>结构的标签时,使用创建的自定义接口
    digester.addRule("Server/Service/Connector",new ConnectorCreateRule());
    

    为单个标签添加规则组(多个标签规则)

    当需要某个xml规则添加多个规则时可以使用RuleSet

    1 创建一个RuleSet实现类,该类需要继承RuleSetBase

    2 构造方法中需要定义xml规则

    3 实现addRuleInstances方法对传入的规则添加规则

    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.addRuleSet( new MyRuleSet( "baz/" ) );
    

    内置的规则接口

    Digester内置了一些规则,可以调用使用DigesterAPI 直接调用,给指定xml添加内置规则。

    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节点,并放入栈。
    

    DEMO

    <?xml version="1.0" encoding="utf-8" ?>
    <department name="deptname001" code="deptcode001">
    <user name="username001" code="usercode001"></user>
    <user name="username002" code="usercode002"></user>
    <extension>
        <property-name>director</property-name>
        <property-value>joke</property-value>
    </extension>
    </department>
    
    
    package com.wuhao.web.tomcat.digester;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    public class Department {
    
        private String name;
    
        private String code;
    
        private Map<String, String> extension = new HashMap<String, String>();
    
        private List<User> users = new ArrayList<User>();
    
        public void addUser(User user){
            this.users.add(user);
        }
    
        public void putExtension(String name,String value){
            this.extension.put(name,value);
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getCode() {
            return code;
        }
    
        public void setCode(String code) {
            this.code = code;
        }
    
        public Map<String, String> getExtension() {
            return extension;
        }
    
        public void setExtension(Map<String, String> extension) {
            this.extension = extension;
        }
    
        public List<User> getUsers() {
            return users;
        }
    
        public void setUsers(List<User> users) {
            this.users = users;
        }
    }
    
    package com.wuhao.web.tomcat.digester;
    
    public class User {
        private String name;
        private String code;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getCode() {
            return code;
        }
    
        public void setCode(String code) {
            this.code = code;
        }
    }
    
    
    package com.wuhao.web.tomcat.digester;
    
    import org.apache.tomcat.util.digester.Digester;
    
    import java.io.File;
    import java.net.URL;
    
    public class DigesterRule {
    
        public Department execute(String filePath) throws Exception {
            Digester digester = new Digester();
            digester.setValidating(false);
            digester.setRulesValidation(true);
    
            // addObjectCreate方法的意思是碰到xml文件中的department节点则创建一个Department对象
            digester.addObjectCreate("department", "com.wuhao.web.tomcat.digester.Department");
            // addSetProperties方法的意思是根据department节点中的属性信息调用相应属性的setter方法
            digester.addSetProperties("department");
            // addObjectCreate方法的意思是碰到xml文件中的department节点则创建一个Department对象
            digester.addObjectCreate("department/user", "com.wuhao.web.tomcat.digester.User");
            digester.addSetProperties("department/user");
    
            digester.addSetNext("department/user", "addUser", "com.wuhao.web.tomcat.digester.User");
            digester.addCallMethod("department/extension", "putExtension", 2);
            digester.addCallParam("department/extension/property-name", 0);
            digester.addCallParam("department/extension/property-value", 1);
            URL url = this.getClass().getClassLoader().getResource(filePath);
            return (Department) digester.parse(new File(url.getFile()));
        }
    }
    
    
    public class Test {
    
        @org.junit.Test
        public void testJavaRule() throws Exception {
            Department department = new DigesterRule().execute("tomcat/department.xml");
            System.out.println(department);
        }
    }
    

    相关文章

      网友评论

          本文标题:Tomcat相关技术-Digester(二)Digester使用

          本文链接:https://www.haomeiwen.com/subject/xjgvdctx.html