使用Digester简化XML文件处理

此篇为译文,原文请参考:

http://www.javaworld.com/article/2074684/learn-java/simplify-xml-file-processing-with-the-jakarta-commons-digester.html


Apache官网提供了很多著名的开源项目,包括Tomcat,Ant,log4j等。Commons是一个名气不大的子项目,包括很多可重用的Java组件。利用这些组件,比如,BeanUtils、DBCP、Logging,你可以简化一些标准化的编程工作。文本关注的是Digester,一个可以将XML文件映射为Java对象的工具。


注意:为了使用Digester,你必须将如下库文件(jar包)添加到classpath中:

  (1) BeanUtils, 
  (2) Collections, 
  (3) Logging, 
  (4) An XML parser conforming to SAX (Simple API for XML) 2.0 or JAXP (Java API for XML Parsing) 1.1.


XML文件解析概述

解析XML文档有两种基本方式。第一种,DOM(Document Object Model)方式。使用这种方式,解析器会读取整个文档并创建一个与之对应的树形结构。第二种,SAX方式,以事件驱动来(events)解析文档。第一种方式易实现,但比起SAX方式,速度慢,耗费资源。Digester通过提供一个高层次的SAX事件接口来简化SAX解析方式。这个接口隐藏了XML文档导航的复杂性,使得开发人员可以将精力集中到处理XML数据上来。


Digester的概念

Digester引入了3个重要的概念:
  (1) 元素匹配模式
  (2) 处理规则
  (3) 对象栈


元素匹配模式将XML元素和处理规则联系在一起。下面的例子展示了一些元素匹配模式所对应的XML层级(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>


如果找到一个元素匹配模式,那么与之对应的处理规则就被激活。在上面的例子中,与'datasources/datasource'模式相对应的规则被执行两次。处理规则定义了当Digester匹配到一个模式时将发生的事件。Digester内置了一些预定义的规则。你也可以编写org.apache.commons.digester.Rule的子类来实现自定义的规则。利用对象栈,你可以通过操控处理规则来获取最终的Java对象。对象可以被添加到栈中,也可以从栈中移除,既可以手动实现,也可以通过处理规则自动实现。


使用Digester

Digester通常用于解析XML配置文件。如下例所示,假设有一个XML配置文件,包含数据源配置信息。另有一个DataSource类,它包括一个默认构造函数和一些getter/setter方法,我们的目标是将XML文件中的信息转换为程序中的DataSource对象。

XML文件示例:

<?xml version="1.0"?>
<datasources>
    <datasource>
        <name>HsqlDataSource</name>
        <driver>org.hsqldb.jdbcDriver</driver>
        <url>jdbc:hsqldb:hsql://localhost</url>
        <username>sa</username>
        <password>lion</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>

DataSource类示例:

public class DataSource {
    private String name;
    private String driver;
    private String url;
    private String userName;
    private String password;

    public DataSource() {
        System.out.println("call the default constructor");
    }
    
    public DataSource(String name, 
String driver, String url, 

                      String userName, String password) {

        this.name = name;
        this.driver = driver;
        this.url = url;
        this.userName = userName;
        this.password = password;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        System.out.println("current name: " + name);
        this.name = name;
    }

    public String getDriver() {
        return driver;
    }

    public void setDriver(String driver) {
        System.out.println("current driver: " + driver);
        this.driver = driver;
    }

    public String getURL() {
        return url;
    }

    public String getUserName() {
        return userName;
    }

    public String getPassword() {
        return password;
    }
}


为了使用Digester,你需要先构造一个Digester实例,然后将你需要的对象放到Digester的对象栈中,添加处理规则,最后一步是解析文件,如下:

public class BadDigester {
    public static void main(String[] args) throws IOException, SAXException {
        // TODO Auto-generated method stub
        Digester digester = new Digester();

        digester.addObjectCreate("datasources/datasource", "DataSource");
        digester.addCallMethod("datasources/datasource/name", "setName", 0);
        digester.addCallMethod("datasources/datasource/driver", "setDriver", 0);
        
        String path = SampleDigester.class.getClassLoader().getResource("datasource.xml").getPath();
        InputStream is = new FileInputStream(path);
        BufferedInputStream bis = new BufferedInputStream(is);
        digester.parse(bis);
        bis.close();
    }
} // BadDigester


在这个例子中,addObjectCreate()方法为'datasources/datasource'模式添加一个对象创建规则。这个规则创建一个DataSource类的实例并把这个实例放到Digester的对象栈中。然后,addCallMethod()方法为两个模式添加调用方法规则,这个规则调用处于对象栈顶的对象的方法。addCallMethod()的最后一个参数指定了传给被调方法的附加参数的个数。这里是0,因此只有匹配元素的主体被传入方法中。如果将这段代码应用于上述XML文件,将会看到:

  一个DataSource对象被创建,并被添加到对象栈中,

  这个对象的setName方法被调用,参数是HsqlDataSource,

  这个对象的setDriver方法被调用,参数是org.hsqldb.jdbcDriver。

在datasource元素结尾处,对象被弹出对象栈,然后开始一个新的处理周期。


这段示例存在一个问题,对象创建规则会在元素结尾处将与之对应的对象弹出对象栈。这样,当Digester解析完文档后,只有最后一个对象被保留下来。为解决这个问题,可以在解析开始前,往对象栈内添加一个对象,然后调用这个对象的方法来创建你实际需要的对象,下面是一个示例类:

public class SampleDigester {
    private Hashtable dataSources = new Hashtable();

    public static void main(String[] args) {
        SampleDigester sample = new SampleDigester();
        try {
            sample.run();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void run() throws IOException, SAXException {
        Digester digester = new Digester();
        digester.push(this);
        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);

        String path = SampleDigester.class.getClassLoader().getResource("datasource.xml").getPath();
        InputStream is = new FileInputStream(path);
        BufferedInputStream bis = new BufferedInputStream(is);
        digester.parse(bis);
        bis.close();

        System.out.println("total dataSources: " + dataSources.size());
    }

    public void addDataSource(String name, String driver, String url, String userName, String password) {
        DataSource dataSource = new DataSource(name, driver, url, userName, password);
        dataSources.put(name, dataSource);
        System.out.println("DataSource added: " + name);
    }
}

在这个类中,当'datasources/datasource'模式匹配时,addDataSource()方法会被调用。addCallParam()方法会添加调用参数规则,这个规则会把匹配元素的主体作为addDataSource()方法的参数。在addDataSource()方法中,你可以创建真正的DataSource对象,并将它们保存起来。


结语

虽然最初开发Digester是为了简化解析XML配置文件,但它可以用于任何你想将XML文件映射为Java对象的情况。本文仅仅给出一个简介。获取更多信息,可以参考Apache Commons官方网站。另外,原文还提供了一些有关Digester的实用参考示例和源码的链接。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值