Apache开源项目之2[Digester的使用]

    技术2026-01-07  5

    之前的工作经常用到struts1框架,但是说实话,里面的具体实现确实不甚清楚,于是乎今天在看ActionServlet初始化资源的时候整理了一下Digester的使用。要系统的理解Digester可能还得在SAX上费些时间。我这里只是把几个简单的应用罗列一下,希望对自己和别人都有所帮助。

     

    Digester是基于SAX之上的一种简化XML解析逻辑的一个开源项目,来源于 Strut1的项目。

    Digester在处理xml文件的时候主要分成以下几步:

     

    实例化一个Digester实例,为digester添加一些属性(如nameSpace,validate等),接着是为digester添加rule规则,最后将目标xml文件转换为InputStream给digester解析。

     

    Digester中各种各样的rule是Digester之所以如此灵活运用的根本。

     

    在介绍解析的例子之前还有一点需要声明,Digester在解析对象是是利用栈(Stack)原理来处理方法的作用对象的。

     

    接着我们从2个例子来介绍,2中典型的解析XML的方法(前一种是针对InnerText类型的XML,后一种是针对property格式的XML)。

     

    先来看第一种解析:

    ServletBean.java

    public class ServletBean { private String servletName; private String servletClass; private Map<String, String> paramMap; public Map<String, String> getParamMap() { return paramMap; } public String getServletClass() { return servletClass; } public void setServletClass(String servletClass) { this.servletClass = servletClass; } public String getServletName() { return servletName; } public void setServletName(String servletName) { this.servletName = servletName; } public void setParamInfo(String name, String value) { if (paramMap == null) { paramMap = new HashMap<String, String>(); } paramMap.put(name, value); } }

     

    test1.xml

    <?xml version="1.0" encoding="UTF-8"?> <web-app> <servlet> <servlet-name>testServlet</servlet-name> <servlet-class>digester.TestServlet</servlet-class> <init-param> <param-name>config</param-name> <param-value>/WEB-INF/test.xml</param-value> </init-param> <init-param> <param-name>convertNull</param-name> <param-value>yes</param-value> </init-param> </servlet> </web-app>

     

    处理方法:

    public void digester1() throws Exception{ InputStream is = this.getClass().getResourceAsStream("test1.xml"); Digester digester = new Digester(); digester.addObjectCreate("web-app/servlet", "digester.ServletBean"); digester.addCallMethod("web-app/servlet/servlet-name", "setServletName", 0); digester.addCallMethod("web-app/servlet/servlet-class", "setServletClass", 0); digester.addCallMethod("web-app/servlet/init-param", "setParamInfo", 2); digester.addCallParam("web-app/servlet/init-param/param-name", 0); digester.addCallParam("web-app/servlet/init-param/param-value", 1); ServletBean servletBean = (ServletBean)digester.parse(is); System.out.println(servletBean.getParamMap()); }

     

    根据最后的处理方法我们来做一番分析:

    1.当碰到pattern为web-app/servlet时候,创建一个ServletBean实例压如栈中。

    2.当碰到pattern为web-app/servlet-name的时候,寻找当前占类引用(ServletBean引用)的setServletName方法,该方法参数个数为0.

    3.当碰到pattern为web-app/servlet/init-param的时候,寻找当前栈引用并调用其方法setParamInfo该方法有2个参数。

    4.将符合web-app/servlet/init-param/param-name的pattern元素内容作为第0个参数设置到setParamInfo方法中。

    5.最后将xml文件以InputStream的形式送给digester解析。处理完毕后返回栈顶类的引用(ServletBean),进而可以获得当中的内容。

     

     

     

    再来看第2种解析:

    Foo.java

    public class Foo { private String name; private List<Bar> barList = new ArrayList<Bar>(); public String getName() { return name; } public void setName(String name) { this.name = name; } public void addBar(Bar bar) { barList.add(bar); } public List<Bar> getBarList() { return barList; } }

     

    Bar.java

    public class Bar { private String id; private String title; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } }

     

    test2.xml

    <?xml version="1.0" encoding="UTF-8"?> <foo name="The Parent"> <bar id="123" title="The First Child" /> <bar id="456" title="The Second Child" /> </foo>

     

    处理方法:

    InputStream is = this.getClass().getResourceAsStream("test2.xml"); Digester digester = new Digester(); digester.addObjectCreate("foo", "digester.Foo"); digester.addSetProperties("foo"); digester.addObjectCreate("foo/bar", "digester.Bar"); digester.addSetProperties("foo/bar"); digester.addSetNext("foo/bar", "addBar", "digester.Bar"); Foo foo = (Foo)digester.parse(is); System.out.println(foo.getBarList().size());

     

    我们来对第2中解析XML的方法做下分析:

    1.遇到pattern匹配foo时候创建一个Foo对象,并压入栈中。

    2.定义foo下属性到Foo对象成员变量的映射。

    3.当遇到pattern为foo/bar的时候。创建一个Bar元素,再将Bar元素压入堆栈中。

    4.定义bar下属性到Bar对象成员变量的映射。

    5.完成一个Bar映射后,从栈里弹出Bar引用,这时栈的peek值为Foo的引用,于是addSetNext方法告诉我们,调用Foo对象引用的addBar元素,参数为Bar类的引用。

    6.当把所有的映射处理完毕之后再弹出Foo对象。

    7.digester处理完成后返回最外层的Foo对象的实例引用。

     

     

    以上介绍了2种解析XML的方法,然后还更大家分享一种方法,就是digester的addRuleSet(RuleSet)方法,这个方法的参数是一个需要继承RuleSetBase的自定义类。并且要自己实现addRuleInstances(digester)方法,将digester的具体逻辑写在该回调方法里面即可。

     

    至于命名空间的设置以及验证,在本文中不做详细解释。

     

    希望以上总结的内容对大家有所帮助。

     

    参考资料:http://commons.apache.org/digester/commons-digester-1.8/docs/api/org/apache/commons/digester/package-summary.html

     

     

    最新回复(0)