通过XML指定规则
在前面的内容中,我们用程序代码的方式指定模式和规则,这些模式和规则都是在编译的时候就已经确定,虽然从概念上来讲比较简单,但却不能说尽善尽美:Digester框架的总体目标是在运行时识别和处理各种数据结构,但如果我们用编程的方法指定模式和规则,则所有行为在编译时已经固定!如果Java源程序中包含了大量固定的字符串,通常意味着程序在执行某些配置操作,这部分操作可以被(或许是应该被)延迟到运行时进行。
org.apache.commons.digester.xmlrules包解决了这个问题。这个包提供了一个DigesterLoader类,它能够从XML文档读取模式/规则对,返回配置好的Digester对象。用来配置Digester对象的XML文档必须遵从digester-rules.dtd,这个DTD是xmlrules包的一部分。
下面就是本文例子的配置文件rules.xml。有几点必须说明。
首先,模式可以用两种方式指定:或者使用<pattern>元素,或者通过代表规则的XML元素的属性。这两种办法可以混合使用,且<pattern>元素是可以嵌套的。
其次,<alias>元素和<set-properties-rule>一起使用,用来把XML属性映射到Bean属性。
最后,就当前发行的Digester软件包而言,我们不能在配置文件中指定BeanPropertySetterRule,正如前面所介绍的,我们用CallMethodRule来达到同样的目标。
<?xml version="1.0"?>
<digester-rules>
<object-create-rule pattern="catalog" classname="Catalog" />
<set-properties-rule pattern="catalog">
<alias attr-name="library" prop-name="library" />
</set-properties-rule>
<catalog library="somewhere">
<pattern value="catalog/book">
<object-create-rule classname="Book" />
<call-method-rule pattern="author" methodname="setAuthor" paramcount="0" />
<call-method-rule pattern="title" methodname="setTitle" paramcount="0" />
<set-next-rule methodname="addBook" />
</pattern>
<pattern value="catalog/magazine">
<object-create-rule classname="Magazine" />
<call-method-rule pattern="name" methodname="setName" paramcount="0" />
<pattern value="article">
<object-create-rule classname="Article" />
<set-properties-rule>
<alias attr-name="page" prop-name="page" />
</set-properties-rule>
<call-method-rule pattern="headline" methodname="setHeadline" paramcount="0" />
<set-next-rule methodname="addArticle" />
</pattern>
<set-next-rule methodname="addMagazine" />
</pattern>
</digester-rules>
现在,所有实际的操作都转移到了Digester和DigesterLoader类,XmlRulesDriver类就变得相当简单。运行下面的XmlRulesDriver时,在第一个命令行参数中指定目录文档的名字,在第二个参数中指定rules.xml(注意,DigesterLoader不是从File或者org.xml.sax.InputSource读取rules.xml文件,而是要求指定一个URL,因此,下面代码中File引用被转换成了等价的URL)。
public class XmlRulesDriver {
public static void main(String[] args) {
try {
File input = new File("tt.xml");
File rules = new File("aa.xml");
Digester digester = DigesterLoader.createDigester(rules.toURL());
Catalog catalog = (Catalog) digester.parse(input);
System.out.println(catalog.toString());
} catch (Exception exc) {
exc.printStackTrace();
}
}
}