digester来解析xml

想弄清楚struts1到底是怎么解析struts-config.xml文件。于是在源代码中发现用的是apache的Digester库。第一次接触这个,于是好好的查阅了一番。
下面的代码,是从http://soft901.iteye.com/blog/335452上面弄过来的,自己改造了一下,只为了自己更清楚的理解。
待读取的XML文件datasource.xml:

Java代码
<?xml version="1.0"?> 
<datasources> 
    <datasource> 
        <name>mysqldatasource</name> 
        <driver>com.jdbc.mysql.Driver</driver> 
        <url>jdbc:mysql://localhost:3306/test</url> 
        <username>root</username> 
        <password>1234</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> 
此xml文件分2层结构,分别为:

<datasources>节点 其下包含2个<datasource>节点
<datasource>节点,其下包含各种信息节点 : 如:<name> 、<url>等。
我们的操作目标是把datasource中的信息节点的内容提取出来。
把每个<datasource>看做为一个对象,<datasource>中信息节点的内容为对象中的元素。
设定一个类DatasourceConfig.java 其内容如下:

Java代码
package xmlParse.digester; 
 
public class DataSourceConfig { 
    private String name; 
    private String driver; 
    private String url; 
    private String username; 
    private String password; 
 
    public String getName() { 
        return name; 
    } 
 
    public String getDriver() { 
        return driver; 
    } 
 
    public String getUrl() { 
        return url; 
    } 
 
    public String getUsername() { 
        return username; 
    } 
 
    public String getPassword() { 
        return password; 
    } 
 
    public void setName(String name) { 
        this.name = name; 
    } 
 
    public void setDriver(String driver) { 
        this.driver = driver; 
    } 
 
    public void setUrl(String url) { 
        this.url = url; 
    } 
 
    public void setUsername(String username) { 
        this.username = username; 
    } 
 
    public void setPassword(String password) { 
        this.password = password; 
    } 
     
     public String toString() {   
            return "DataSource : " + "name : " + name + " Driver : " + driver   
                    + " URL : " + url + " Username : " + username + " Password : "   
                    + password;   
     }   


其中设置解析的rule规则的方法有四种,一一列出代码。

第一种 使用addCallMethod方法,映射XML所对应的节点与这个Call method的参数即可,这个call method将读取的一个标签内所有的值存入对象,然后再存入一个集合中。


Java代码
package xmlParse.digester; 
/**
* 利用digester来解析xml.
*/ 
import java.io.IOException; 
import java.util.ArrayList; 
import java.util.List; 
 
import org.apache.commons.digester.Digester; 
import org.xml.sax.SAXException; 
 
public class DigesterParseTest { 
    private List<DataSourceConfig> dataSources; 
 
    public static void main(String[] args) { 
        DigesterParseTest sd = new DigesterParseTest(); 
        sd.digester(); 
        System.out.println(sd.toString()); 
    } 
 
    void digester() { 
        Digester digester = new Digester(); 
        setDataSources(new ArrayList<DataSourceConfig>()); 
        // 把当前对象压入到digester栈中。 
        digester.push(this); 
        /* 设定解析此xml文件的规则 */ 
        // 将XML文件解析所对应的方法.this.addDataSource();参数个数为5个. 
        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); 
 
        try { 
            digester.parse("config/datasource.xml"); 
        } catch (IOException e) { 
            e.printStackTrace(); 
        } catch (SAXException e) { 
            e.printStackTrace(); 
        } 
    } 
     
    public void addDataSource(final String name, final String driver, 
            final String url, final String username, final String password) { 
        DataSourceConfig dataSource = new DataSourceConfig(); 
        dataSource.setName(name); 
        dataSource.setDriver(driver); 
        dataSource.setUrl(url); 
        dataSource.setUsername(username); 
        dataSource.setPassword(password); 
        getDataSources().add(dataSource); 
    } 
     
    public List<DataSourceConfig> getDataSources() { 
        return dataSources; 
    } 
 
    public void setDataSources(List<DataSourceConfig> dataSources) { 
        this.dataSources = dataSources; 
    } 
 
    public String toString() { 
        String newline = System.getProperty("line.separator"); 
        StringBuffer buff = new StringBuffer(); 
        if (getDataSources() != null) { 
            for (DataSourceConfig ds : getDataSources()) { 
                buff.append(newline).append(ds); 
            } 
            return buff.toString(); 
        } 
        return ""; 
    } 



第二种 使用addObjectCreate方法,创建对象映射XML文件的属性对java Bean. 读取完一个对象将对象加入到一个集合中,然后再读取XML文件的下一个标签:

Java代码
package xmlParse.digester; 
/**
* 利用digester来解析xml.
*/ 
import java.io.IOException; 
import java.util.ArrayList; 
import java.util.List; 
 
import org.apache.commons.digester.Digester; 
import org.xml.sax.SAXException; 
 
public class DigesterParseTest2 { 
    private List<DataSourceConfig> dataSources; 
 
    public static void main(String[] args) { 
        DigesterParseTest sd = new DigesterParseTest(); 
        sd.digester(); 
        System.out.println(sd.toString()); 
    } 
    private void digester() { 
        Digester digester = new Digester(); 
        setDataSources(new ArrayList<DataSourceConfig>()); 
        // 把当前对象压入到digester栈中。 
        digester.push(this); 
         
        /* 设定解析此xml文件的规则 */ 
        digester.addObjectCreate("datasources/datasource", DataSourceConfig.class); 
         
        //效果跟addSetProperties一样 
//      digester.addBeanPropertySetter("datasources/datasource/name","name"); 
//      digester.addBeanPropertySetter("datasources/datasource/driver", "driver"); 
//      digester.addBeanPropertySetter("datasources/datasource/url", "url"); 
//      digester.addBeanPropertySetter("datasources/datasource/username", "username"); 
//      digester.addBeanPropertySetter("datasources/datasource/password", "password"); 
Java代码
        digester.addSetProperties("datasources/datasource/name"); 
        digester.addSetProperties("datasources/datasource/driver"); 
        digester.addSetProperties("datasources/datasource/url"); 
        digester.addSetProperties("datasources/datasource/username"); 
        digester.addSetProperties("datasources/datasource/password"); 
        digester.addSetNext("datasources/datasource", "addDataSource"); 
        try { 
            digester.parse("config/datasource.xml"); 
        } catch (IOException e) { 
            e.printStackTrace(); 
        } catch (SAXException e) { 
            e.printStackTrace(); 
        } 
    } 
     
    public void addDataSource(final DataSourceConfig datasource){ 
        getDataSources().add(datasource); 
    } 
    public List<DataSourceConfig> getDataSources() { 
        return dataSources; 
    } 
 
    public void setDataSources(List<DataSourceConfig> dataSources) { 
        this.dataSources = dataSources; 
    } 
 
    public String toString() { 
        String newline = System.getProperty("line.separator"); 
        StringBuffer buff = new StringBuffer(); 
        if (getDataSources() != null) { 
            for (DataSourceConfig ds : getDataSources()) { 
                buff.append(newline).append(ds); 
            } 
            return buff.toString(); 
        } 
        return ""; 
    } 



第三种:使用addRule方法来解析datasource.xml:

Java代码
private void digester() { 
    Digester digester = new Digester(); 
 
    setDataSources(new Vector<DataSource>()); 
    // 把当前对象压入到digester栈中。 
    digester.push(this); 
 
    Rule objectCreate = new ObjectCreateRule(DataSource.class); 
    digester.addRule("datasources/datasource", objectCreate); 
 
    digester.addRule("datasources/datasource", new SetNextRule( 
            "addDataSource")); 
 
    digester.addRule("datasources/datasource/name", new CallMethodRule( 
            "setName", 0, new Class[] { String.class })); 
    digester.addRule("datasources/datasource/driver", new CallMethodRule( 
            "setDriver", 0, new Class[] { String.class })); 
    digester.addRule("datasources/datasource/url", new CallMethodRule( 
            "setUrl", 0, new Class[] { String.class })); 
    digester.addRule("datasources/datasource/username", new CallMethodRule( 
            "setUsername", 0, new Class[] { String.class })); 
    digester.addRule("datasources/datasource/password", new CallMethodRule( 
            "setPassword", 0, new Class[] { String.class })); 
    try { 
        digester.parse("datasource.xml"); 
    } catch (IOException e) { 
        e.printStackTrace(); 
    } catch (SAXException e) { 
        e.printStackTrace(); 
    } 



第四种:把规则写在xml文件中。新建rules.xml

Java代码
<? xml version = " 1.0 " ?> 
<digester-rules> 
    <object-create-rule pattern=" datasources " 
        classname=" datasources " /> 
    <pattern value=" datasources/datasource "> 
        <object-create-rule classname=" datasource " /> 
        <call-method-rule pattern=" name " methodname=" setName " 
            paramcount=" 0 " /> 
        <call-method-rule pattern=" driver " methodname=" setDriver " 
            paramcount=" 0 " /> 
        <call-method-rule pattern=" url " methodname=" setUrl " 
            paramcount=" 0 " /> 
        <call-method-rule pattern=" username " methodname=" setUsername " 
            paramcount=" 0 " /> 
        <call-method-rule pattern=" password " methodname=" setPassword " 
            paramcount=" 0 " /> 
        <set-next-rule methodname=" addDatasource " /> 
    </pattern> 
     
</digester-rules> 

digester方法如下:

Java代码
private void digester() { 
        setDataSources(new ArrayList<DataSourceConfig>()); 
        try { 
            File rules = new File("config/rules.xml"); 
            //创建digester对象并指定解析规则 
            Digester digester = DigesterLoader.createDigester(rules.toURL()); 
            digester.parse("config/datasource.xml"); 
        } catch (IOException e) { 
            e.printStackTrace(); 
        } catch (SAXException e) { 
            e.printStackTrace(); 
        } 
    } 

以上是digester四种解析xml的方法。这些例子只是些直观的说明。竹笋炒肉的三篇有关digester的笔记更深入一步的讲解了有关digester的知识。链接见下:
digester学习笔记1
digester学习笔记2
digester学习笔记3
另附上commons-digester-2.0 API和官网

回到文章开头说的,其实了解digester是为了弄明白struts怎么解析配置文件的。本来想自己整理下,但是发现struts学习--初始化MoudleConfig 正好解释的很清楚,只以解析DataSourceConfig标签为例稍微补充下RuleSet配置说明。
Java代码
通过ActionServlet的成员变量configDigester的初始化来深入理解struts-config.xml文件的加载,其中配置信息可以通过org.apache.struts.config.impl.ModuleConfigImpl类描述。  
 
configDigester上注册了RuleSet类为ConfigRuleSet,主要通过覆盖方法public void addRuleInstances(Digester digester)来为digester注册Rule,代码分析如下:  
 
1.处理ModuleConfigImpl对象中的数据源DataSourceConfig对象:  
/* 1.1当遇到struts-config/data-sources/data-source开始标记时便创建此标记className属性标示的类实例,如果没有className属性,则创建org.apache.struts.config.DataSourceConfig对象,并入栈;遇到结束标记时对象出栈。*/  
 
digester.addObjectCreate  
("struts-config/data-sources/data-source", "org.apache.struts.config.DataSourceConfig", "className");  
/*1.2 当遇到struts-config/data-sources/data-source开始标记时根据data-source标记的属性设置栈顶元素对象的属性 */  
digester.addSetProperties  
("struts-config/data-sources/data-source");  
 
/*1.3 遇到struts-config/data-sources/data-source结束标记时将调用次栈顶元素ModuleConfigImpl对象的addDataSourceConfig方法,将当前栈顶元素DataSourceConfig对象为值,struts-config/data-sources/data-source标记的key属性为键推入到ModuleConfigImpl的HashMap类型成员变量dataSources中。*/  
digester.addSetNext  
("struts-config/data-sources/data-source", "addDataSourceConfig", "org.apache.struts.config.DataSourceConfig");  
 
/*1.4 将遇到的set-property标记的property属性值为key,value属性值为值添加到栈顶DataSourceConfig对象的HashMap类型成员变量properties中。*/ digester.addRule  
("struts-config/data-sources/data-source/set-property", new AddDataSourcePropertyRule());  

你可能感兴趣的:(apache,oracle,xml,mysql,struts)