digester使用
来源:互联网 发布:知乎中国出口构成 编辑:程序博客网 时间:2024/05/23 11:32
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配置文件的功能了。
- digester使用
- org.apache.commons.digester.Digester使用
- 使用Digester的感受
- Digester的使用
- Digester 组件使用简介
- 使用Digester解析xml
- commons-digester使用
- Digester简单使用
- digester
- Digester
- Digester
- 使用digester 解析xml配置文件
- Apache Commons Digester 使用实例
- Jakarta-Common-Digester使用笔记
- 使用Digester解析XML配置文件
- 使用Digester解析XML文档
- Tomcat中使用的组件-Digester组件
- [Java学习]使用digester 解析xml配置文件
- UVa227 Puzzle
- 如何移植μC/GUI在OLED12864上显示
- java数据写入数据库错误
- 基于c#环境的单片机和PC串口通信
- Linux spi驱动 (一)
- digester使用
- Android Annotations 4.0.0 配置Rest API
- [58] Length of Last Word
- UVa1601 万圣节后的早晨(The Morning after Halloween)
- 静态存储区的内存四区
- HDU 4528 (BFS)
- Oracle查询昨天的记录
- leetcode 357. Count Numbers with Unique Digits 解题报告
- codeforces round 359# div.2 B. Little Robber Girl's Zoo