读代码最大的迷惑来自与 digester,由于之前没有用过,所以就在网上抓来了一片文章学习一下,具体内容如下:
xml解析简介
总的来说,xml文件解析有2种基本方法。一种是dom(document object model)方法。采用dom方法进行解析时,xml解析器读取整个xml文件并生成一个树状表达方式。另一个是使用sax,它的特点是不需要遍历整个文 件而是用事件驱动来解析文件。虽然dom方法有时实现起来比较容易,但是与sax方法相比速度更慢而且更耗资源。digester构件通过为sax事件提 供高级的接口大大简化了sax方法的解析过程。该接口隐含了大量xml文件处理的复杂的技术细节。使开发人员得以集中精力处理xml数据而不是花太多的时 间在如何解析文件本身上。
digester的几个重要概念
digester引入了3个重要概念:元素匹配模式,处理规则以及对象栈。
元素匹配模式将处理规则与xml元素联系起来。以下是一个xml层次结构的元素匹配模式的例子。
<datasources> 'datasources' <datasource> 'datasources/datasource' <name/> 'datasources/datasource/name' <driver/> 'datasources/datasource/driver' </datasource> <datasource> 'datasources/datasource' <name/> 'datasources/datasource/name' <driver/> 'datasources/datasource/driver' </datasource> </datasources> |
每当发现一个匹配的模式(也可称层次),对应的处理规则就被激活。在上面的示例中,与'datasource/datasource'相关联的规则将会运行2次。
处理规则定义了发现匹配的模式时产生的行为。digester模块已经预定了不少处理规则,自定义的处理规则可以通过扩展 org.apache.commons.digester.rule类来实现。
对象栈用来保存处理规则所要处理的对象。对象可以由人为或处理规则压入和弹出对象栈。
使用digester
digester 时常用于解析xml配置文件,下面例子中的xml文件包含了用于创建datasource池的配置信息。 其中datasource是抽象类,拥有一个空的构造函数,多个get,set方法来存取字符串。
<?xml version="1.0"?> <datasources> <datasource> <name>hsqldatasource</name> <driver>org.hsqldb.jdbcdriver</driver> <url>jdbc:hsqldb:hsql://localhost</url> <username>sa</username> <password></password> </datasource> <datasource> <name>oracledatasource</name> <driver>oracle.jdbc.driver.oracledriver</driver> <url>jdbc:oracle:thin:@localhost:1521:orcl</url> <username>scott</username> <password>tiger</password> </datasource> </datasources> | |
要使用digester对之进行解析,首先我们要创建一个digester类的实例,然后把所需的对象都压入到digester对象栈中,设置一系列处理规则,最后,对文件进行解析。下面是一个例子:
digester digester = new digester(); /** *addobjectcreate()创建一个新的datasource类的实例并把它压入digester的对象栈中。 */ digester.addobjectcreate("datasources/datasource", "datasource"); /**addcallmethod()调用位于对象栈顶部的对象的特定的方法,addcallmethod()的最后一个参数指定了传入*该方法的参数数目,如果 数目为0则匹配上的数据项内容将作为参数传入。 *下面这句代码实际就是调用datasource对象中的setname方法,传入的参数就是xml文件中*"datasources/datasource/name"对应的值 */ digester.addcallmethod("datasources/datasource/name","setname",0); digester.addcallmethod("datasources/datasource/driver","setdriver", 0); /**解析随后的内容*/ digester.parse("datasource.xml"); |
(注:类objectcreaterule,callmethodrule 都是digester模块已定义的处理规则)
假如应用这个代码段来处理在前面提到的xml文件,将会发生以下结果:
· 一个新的datasource类的实例将被创建并压入堆栈;
· 调用该实例的setname(string name)方法,参数值为'hsqldatasource';
· 调用该实例的setdriver(string driver)方法,参数值为'oracledatasource'。
在对'datasource'元素的处理结束后,对象从堆栈中弹出,文件剩余部分的解析重复以上过程。上面的例子存在一个问题,在对相关元素的处理结 束后,objectcreaterule会弹出它创建的对象。因此,当digester完成解析文件后,只有最后一次创建的对象被保留下来。解决这个问题 也很容易,只要把对象在解析开始之前压入堆栈,随后调用该对象的某个方法来创建所需的任意对象。下面的类就是这个办法的一个演示:
public class sampledigester { public void run() throws ioexception, saxexception { digester digester = new digester(); // this method pushes this (sampledigester) class to the digesters // object stack making its method s available to processing rules. digester.push(this); // this set of rules calls the adddatasource method and passes // in five parameters to the method. digester.addcallmethod ("datasources/datasource", "adddatasource", 5); digester.addcallparam("datasources/datasource/name", 0); digester.addcallparam("datasources/datasource/driver", 1); digester.addcallparam("datasources/datasource/url", 2); digester.addcallparam("datasources/datasource/username", 3); digester.addcallparam("datasources/datasource/password", 4); // this method starts the parsing of the document. digester.parse("datasource.xml"); } // example method called by digester. public void adddatasource(string name, string driver, string url, string username, string password) { // create datasource and add to collection... } } |
在上面的sampledigester类中,每当匹配到 'datasources/datasource'时都会自动调用adddatasource()方法。addcallparam()方法将匹配到的数据 项内容作为传入adddatasource()方法的参数。在adddatasource()方法中,你就可以创建具体的datasouce并把它添加入 你的datasource集合中去。
看完着些我们该进入正题了,看看MenuRepository.java中的代码:
protected Digester initDigester() {
Digester digester = new Digester();
digester.setClassLoader(Thread.currentThread().getContextClassLoader());
digester.push(this);
digester.addObjectCreate("MenuConfig/Menus/Menu",
"com.fgm.web.menu.MenuComponent",
"type");
digester.addSetProperties("MenuConfig/Menus/Menu");
digester.addSetNext("MenuConfig/Menus/Menu", "addMenu");
// 2
digester.addObjectCreate("MenuConfig/Menus/Menu/Item",
"com.fgm.web.menu.MenuComponent",
"type");
digester.addSetProperties("MenuConfig/Menus/Menu/Item");
digester.addSetNext("MenuConfig/Menus/Menu/Item", "addMenuComponent",
"com.fgm.web.menu.MenuComponent");
// 3
digester.addObjectCreate("MenuConfig/Menus/Menu/Item/Item",
"com.fgm.web.menu.MenuComponent",
"type");
digester.addSetProperties("MenuConfig/Menus/Menu/Item/Item");
digester.addSetNext("MenuConfig/Menus/Menu/Item/Item", "addMenuComponent",
"com.fgm.web.menu.MenuComponent");
// 4
digester.addObjectCreate("MenuConfig/Menus/Menu/Item/Item/Item",
"com.fgm.web.menu.MenuComponent",
"type");
digester.addSetProperties("MenuConfig/Menus/Menu/Item/Item/Item");
digester.addSetNext("MenuConfig/Menus/Menu/Item/Item/Item", "addMenuComponent",
"com.fgm.web.menu.MenuComponent");
// 5
digester.addObjectCreate("MenuConfig/Menus/Menu/Item/Item/Item/Item",
"com.fgm.web.menu.MenuComponent",
"type");
digester.addSetProperties("MenuConfig/Menus/Menu/Item/Item/Item/Item");
digester.addSetNext("MenuConfig/Menus/Menu/Item/Item/Item/Item", "addMenuComponent",
"com.fgm.web.menu.MenuComponent");
// 6
digester.addObjectCreate("MenuConfig/Menus/Menu/Item/Item/Item/Item",
"com.fgm.web.menu.MenuComponent",
"type");
digester.addSetProperties("MenuConfig/Menus/Menu/Item/Item/Item/Item");
digester.addSetNext("MenuConfig/Menus/Menu/Item/Item/Item/Item", "addMenuComponent",
"com.fgm.web.menu.MenuComponent");
// 7
digester.addObjectCreate("MenuConfig/Menus/Menu/Item/Item/Item/Item",
"com.fgm.web.menu.MenuComponent",
"type");
digester.addSetProperties("MenuConfig/Menus/Menu/Item/Item/Item/Item");
digester.addSetNext("MenuConfig/Menus/Menu/Item/Item/Item/Item", "addMenuComponent",
"com.fgm.web.menu.MenuComponent");
digester.addObjectCreate("MenuConfig/Displayers/Displayer",
"com.fgm.web.menu.displayer.MenuDisplayerMapping",
"mapping");
digester.addSetProperties("MenuConfig/Displayers/Displayer");
digester.addSetNext("MenuConfig/Displayers/Displayer", "addMenuDisplayerMapping",
"com.fgm.web.menu.displayer.MenuDisplayerMapping");
digester.addSetProperty("MenuConfig/Displayers/Displayer/SetProperty",
"property", "value");
return digester;
}
太晚了,明天接着写。