• xml转对象


    1.   概述

    解析XML一直都是编写程序的头疼问题,不是因为它难,而是因为各种地方需要对解析XML的结果要求不同,XML解析和业务逻辑融合在一起,所以每次解析时都感觉是从头开始,没有一套好用的类库。

    在大多数应用系统中,都需要保存一个或多个配置信息,这些信息可以保存在数据库中,也可以保存在文件中,保存XML文件中是一个不错的选择,如下:

    <?xml version="1.0" encoding="GB18030"?>

    <SystemConfig>

        <LinesPerPage>20</LinesPerPage>

        <ThreadPool>

            <MaxNum>10</MaxNum>

            <MinNum>5</MinNum>

        </ThreadPool>

    </SystemConfig>

    您可能希望在系统运行时,直接从一个JavaBean中读取系统配置信息,JavaBean的结构如下(省略了get/set):

    package bean;

     

    public class SystemConfig

    {

        private int linesPerPage = 0;

     

        private int threadPoolMaxNum = 0;

     

        private int threadPoolMinNum = 0;

    }

    如果简单的将SystemConfig.xml和SystemConfig关联起来呢?commons-digester是一个不错的选择。

    2.   Commons-digester介绍

    2.1. 概述

    Commons-digester是apache的开源类库,最初是struts的一部分,目的是读取struts中的一系列XML文件(如struts-config.xml),后来经过扩充和重构,变成了一个独立的开源库。

    大家都知道,使用struts作为表示层的应用程序往往都包含多个XML文件,每个XML文件的内容都不同,如果为每种文件编写一个XML解析器,将大大加重程序维护的难度,最终可能因为XML解析方式无法维护,导致这个开源项目失败。但struts的开发者很聪明,他们想到了将XML解析抽取出来,统一维护的方式,于是commons-disgester的前身就诞生了。

    Commons-digester可以通过几行简单的代码,将XML文件转换为JavaBean或其他需要的格式。其中,直接转换为JavaBean是最常用的。

    2.2. 基本原理

    Commons-digester将一个XML文件看作一个抽象的栈,当读到一个开始标签时,将标签内容压栈,当读取结束标签时,将栈顶元素出栈,同时执行所有的规则(Rule),以此类推,完成整个XML文件的读取。

    3.   SystemConfig.xml解析方法

    基本原理可能会让广大同行迷惑,直接看一些SystemConfig.xml文件如何解析吧。

    解析XML文件的代码如下,junit部分只是检验解析结果是否正确:

    import java.io.File;

    import java.io.IOException;

     

    import junit.framework.TestCase;

     

    import org.apache.commons.digester.Digester;

    import org.xml.sax.SAXException;

     

    import bean.SystemConfig;

     

     

    public class SystemConfigTest extends TestCase

    {

        public void testSystemConfig() throws IOException, SAXException

        {

           // 生成digester对象

           Digester digester = new Digester();

          

           // 当遇到<SystemConfig>标签时生成SystemConfig对象

           digester.addObjectCreate("SystemConfig", SystemConfig.class);

          

           // 当遇到<SystemConfig><LinesPerPage>标签时为SystemConfig中的linesPerPage属性赋值

           digester.addBeanPropertySetter("SystemConfig/LinesPerPage", "linesPerPage");

          

           // 当遇到<SystemConfig><ThreadPool><MaxNum>标签时为SystemConfig中的threadPoolMaxNum属性赋值     digester.addBeanPropertySetter("SystemConfig/ThreadPool/MaxNum", "threadPoolMaxNum");

          

           // 当遇到<SystemConfig><ThreadPool><MinNum>标签时为SystemConfig中的threadPoolMinNum属性赋值     digester.addBeanPropertySetter("SystemConfig/ThreadPool/MinNum", "threadPoolMinNum");

          

           // 读取SystemConfig.xml文件

           File systemConfigXml = new File("SystemConfig.xml");

           // 进行文件解析

           SystemConfig sysConfig = (SystemConfig)digester.parse(systemConfigXml);

          

          

           // 以下的测试用例用来判断解析结果是否正确

           assertNotNull(sysConfig);

           assertEquals(20, sysConfig.getLinesPerPage());

           assertEquals(10, sysConfig.getThreadPoolMaxNum());

           assertEquals(5, sysConfig.getThreadPoolMinNum());

        }

    }

    要解析一个XML文件,需要先定义好解析规则,然后使用这些预定义规则解析XML文件即可。在上面的例子中,因为解析的结果是将XML中的属性值保存到Bean中,所以直接使用addBeanPropertySetter()方法就可以了。

    从上面的例子可以看出,解析一个XML文件,主要有以下三步:

    1. 创建Digester对象。
    2. 向Digester对象中添加解析规则。
    3. 使用解析规则解析文件。

    4.   XML文件解析规则

    Commons-digester将繁琐的解析过程变成了简单的三个步骤,其实解析不同XML文件时,只有添加规则一步有一些差别,其他两部只要照搬上面的代码即可。

    规则是XML文件的解析方法,也就是Digester对象在遇到不同XML元素时需要执行的操作。比如上面例子中的BeanPropertySetter规则,就是将XML内容保存到Bean的相应元素中。

    规则可以自定义,但在一般情况下,默认的一套规则足以满足大多数场合的需要。

    5.   更复杂的例子

    下面我们来看一个更复杂的例子,在这个例子中,使用commons-digester解析一个web.xml文件,这个文件是我自己写的一个真实项目中的一小部分。

    Web.xml文件如下:

    <?xml version="1.0" encoding="GB18030"?>

     

    <web-app>

        <display-name>Struts Examples Application</display-name>

        <context-param>

           <param-name>contextConfigLocation</param-name>

           <param-value>/WEB-INF/spring-beans-config.xml</param-value>

        </context-param>

     

        <listener>

           <listener-class>

               org.springframework.web.context.ContextLoaderListener

           </listener-class>

        </listener>

     

        <listener>

           <listener-class>

               com.lijin.demo.common.listener.SpringConfigListener

           </listener-class>

        </listener>

     

        <filter>

           <filter-name>encodingFilter</filter-name>

           <filter-class>

               org.springframework.web.filter.CharacterEncodingFilter

           </filter-class>

           <init-param>

               <param-name>encoding</param-name>

               <param-value>UTF-8</param-value>

           </init-param>

           <init-param>

               <param-name>forceEncoding</param-name>

               <param-value>true</param-value>

           </init-param>

        </filter>

       

        <servlet>

           <servlet-name>action</servlet-name>

           <servlet-class>

               org.apache.struts.action.ActionServlet

           </servlet-class>

     

           <init-param>

               <param-name>config</param-name>

               <param-value>/WEB-INF/struts-configs/common-config.xml</param-value>

           </init-param>

           <init-param>

               <param-name>config/jsp/user</param-name>

               <param-value>/WEB-INF/struts-configs/user-config.xml</param-value>

           </init-param>

           <init-param>

               <param-name>config/jsp/usergroup</param-name>

               <param-value>/WEB-INF/struts-configs/usergroup-config.xml</param-value>

           </init-param>

           <load-on-startup>2</load-on-startup>

        </servlet>

     

        <servlet-mapping>

           <servlet-name>action</servlet-name>

           <url-pattern>*.do</url-pattern>

        </servlet-mapping>

     

        <filter-mapping>

           <filter-name>encodingFilter</filter-name>

           <url-pattern>*.html</url-pattern>

        </filter-mapping>

       

        <filter-mapping>

           <filter-name>encodingFilter</filter-name>

           <url-pattern>*.do</url-pattern>

        </filter-mapping>

       

        <filter-mapping>

           <filter-name>encodingFilter</filter-name>

           <url-pattern>*.jsp</url-pattern>

        </filter-mapping>

       

        <welcome-file-list>

           <welcome-file>index.jsp</welcome-file>

        </welcome-file-list>

     

        <taglib>

           <taglib-uri>http://www.lijin.com/tags</taglib-uri>

           <taglib-location>/WEB-INF/tld/lijin.tld</taglib-location>

        </taglib>

    </web-app>

    解析该文件的例子如下:

    import java.io.File;

    import java.io.IOException;

     

    import junit.framework.TestCase;

     

    import org.apache.commons.digester.Digester;

    import org.xml.sax.SAXException;

     

    import bean.Filter;

    import bean.Servlet;

    import bean.WebApp;

     

     

    public class FirstTest extends TestCase

    {

        public void testWebXml() throws IOException, SAXException

        {

           Digester digester = new Digester();

           digester.addObjectCreate("web-app", WebApp.class);

           digester.addBeanPropertySetter("web-app/display-name", "displayName");

          

           digester.addCallMethod("web-app/context-param", "addContextParam", 2);

           digester.addCallParam("web-app/context-param/param-name", 0);

           digester.addCallParam("web-app/context-param/param-value", 1);

          

           digester.addCallMethod("web-app/listener", "addListener", 1);

           digester.addCallParam("web-app/listener/listener-class", 0);

          

           digester.addObjectCreate("web-app/filter", Filter.class);

           digester.addSetNext("web-app/filter", "addFilter");

           digester.addBeanPropertySetter("web-app/filter/filter-name", "filterName");

           digester.addBeanPropertySetter("web-app/filter/filter-class", "filterClass");

           digester.addCallMethod("web-app/filter/init-param", "addInitParam", 2);

           digester.addCallParam("web-app/filter/init-param/param-name", 0);

           digester.addCallParam("web-app/filter/init-param/param-value", 1);

          

           digester.addObjectCreate("web-app/servlet", Servlet.class);

           digester.addSetNext("web-app/servlet", "addServlet");

           digester.addBeanPropertySetter("web-app/servlet/servlet-name", "servletName");

           digester.addBeanPropertySetter("web-app/servlet/servlet-class", "servletClass");

           digester.addCallMethod("web-app/servlet/init-param", "addInitParam", 2);

           digester.addCallParam("web-app/servlet/init-param/param-name", 0);

           digester.addCallParam("web-app/servlet/init-param/param-value", 1);

           digester.addBeanPropertySetter("web-app/servlet/load-on-startup", "loadOnStartUp");

          

           digester.addCallMethod("web-app/servlet-mapping", "addServletMapping", 2);

           digester.addCallParam("web-app/servlet-mapping/servlet-name", 0);

           digester.addCallParam("web-app/servlet-mapping/url-pattern", 1);

          

           digester.addCallMethod("web-app/filter-mapping", "addFilterMapping", 2);

           digester.addCallParam("web-app/filter-mapping/filter-name", 0);

           digester.addCallParam("web-app/filter-mapping/url-pattern", 1);

          

           digester.addCallMethod("web-app/welcome-file-list/welcome-file", "addWelcomeFile", 1);

           digester.addCallParam("web-app/welcome-file-list/welcome-file", 0);

          

           digester.addCallMethod("web-app/taglib", "addTaglib", 2);

           digester.addCallParam("web-app/taglib/taglib-uri", 0);

           digester.addCallParam("web-app/taglib/taglib-location", 1);

          

           File webXml = new File("web.xml");

           WebApp webApp = (WebApp)digester.parse(webXml);

          

           assertNotNull(webApp);

           assertEquals("Struts Examples Application", webApp.getDisplayName());

          

           assertEquals(1, webApp.getContextParamList().size());

           assertEquals("contextConfigLocation", webApp.getContextParamList().get(0).getParamName());

           assertEquals("/WEB-INF/spring-beans-config.xml", webApp.getContextParamList().get(0).getParamValue());

          

           assertEquals(2, webApp.getListenerList().size());

           assertEquals("org.springframework.web.context.ContextLoaderListener", webApp.getListenerList().get(0));

           assertEquals("com.lijin.demo.common.listener.SpringConfigListener", webApp.getListenerList().get(1));

          

           assertEquals(1, webApp.getFilterMap().size());

           assertEquals("encodingFilter", webApp.getFilterMap().get("encodingFilter").getFilterName());

           assertEquals("org.springframework.web.filter.CharacterEncodingFilter", webApp.getFilterMap().get("encodingFilter").getFilterClass());

           assertEquals("UTF-8", webApp.getFilterMap().get("encodingFilter").getEncoding());

           assertEquals(true, webApp.getFilterMap().get("encodingFilter").isForceEncoding());

          

           assertEquals(1, webApp.getServletMap().size());

           assertTrue(webApp.getServletMap().containsKey("action"));

           assertEquals("action", webApp.getServletMap().get("action").getServletName());

           assertEquals("org.apache.struts.action.ActionServlet", webApp.getServletMap().get("action").getServletClass());

           assertEquals(3, webApp.getServletMap().get("action").getConfigMap().size());

           assertTrue(webApp.getServletMap().get("action").getConfigMap().containsKey("config"));

           assertTrue(webApp.getServletMap().get("action").getConfigMap().containsKey("config/jsp/user"));

            assertTrue(webApp.getServletMap().get("action").getConfigMap().containsKey("config/jsp/usergroup"));

           assertEquals("/WEB-INF/struts-configs/common-config.xml", webApp.getServletMap().get("action").getConfigMap().get("config"));

           assertEquals("/WEB-INF/struts-configs/user-config.xml", webApp.getServletMap().get("action").getConfigMap().get("config/jsp/user"));

           assertEquals("/WEB-INF/struts-configs/usergroup-config.xml", webApp.getServletMap().get("action").getConfigMap().get("config/jsp/usergroup"));

           assertEquals(webApp.getServletMap().get("action").getLoadOnStartUp(), 2);

          

           assertEquals(1, webApp.getServletMap().get("action").getMappingUrlList().size());

           assertTrue(webApp.getServletMap().get("action").getMappingUrlList().contains("*.do"));

          

           assertEquals(1, webApp.getFilterMap().size());

           assertEquals(3, webApp.getFilterMap().get("encodingFilter").getMappingUrlList().size());

           assertTrue(webApp.getFilterMap().get("encodingFilter").getMappingUrlList().contains("*.html"));

           assertTrue(webApp.getFilterMap().get("encodingFilter").getMappingUrlList().contains("*.do"));

           assertTrue(webApp.getFilterMap().get("encodingFilter").getMappingUrlList().contains("*.jsp"));

          

           assertEquals(1, webApp.getWelcomeFileList().size());

           assertTrue(webApp.getWelcomeFileList().contains("index.jsp"));

          

           assertEquals(1, webApp.getTagLibMap().size());

           assertTrue(webApp.getTagLibMap().containsKey("http://www.lijin.com/tags"));

           assertEquals("/WEB-INF/tld/lijin.tld", webApp.getTagLibMap().get("http://www.lijin.com/tags"));

        }

       

       

    }

    其中用到了bean.Filter,bean.Servlet和bean.WebApp三个JavaBean,他们都是配合这个例子的标准JavaBean,都可以根据上述文件的结构推倒出来,在这里不赘述。

    6.   学习这个类库的心得

    Commons-Digester为我们解析XML文件提供了一个新思路和新方法,在研究的规程中,我曾经想过为什么只有读取文件的类,没有写文件的类,后来仔细一想,才明白设计这个类库的目的是简化XML文件的读取,相反,写XML文件比读取容易的多,因为整个写文件的过程都在自己的控制之下,能输出什么格式自己心里都有数,读取就没那么容易了需要进行各种各样的校验。实际使用时,在对这套类库进行简单的封装后,就可以实现读写XML配置文件的功能了。

  • 相关阅读:
    【转】职场中如何才能学会心理自控
    Gof《设计模式》完结
    阿里巴巴CEO马云最新超经典哲学语录
    大话设计模式感悟(3)——策略模式(Strategy)
    设计模式 ( 十三 ) 命令模式Command(对象行为型)
    数据结构&算法实践Python——序章
    设计模式 ( 十八 ) 策略模式Strategy(对象行为型)
    设计模式 ( 十六 ) 观察者模式Observer(对象行为型)
    金融系列2《借贷记卡应用》
    php 设计模式数据映射模式(应用程序与数据库交互模式)
  • 原文地址:https://www.cnblogs.com/zhuzhuxuan/p/5816927.html
Copyright © 2020-2023  润新知