三、将XML映射成Java类
Digester类通过模式(patterns)和规则来处理XML文档。其中的模式必须匹配XML元素,也就是在XML文档树中的结点名和位置。Digester中的匹配模式的语法有些类似XPath的匹配模式。如模式catalog匹配最顶层结点<catalog>,模式catalog/book匹配<catalog>结点中的子结点<book>,其它的匹配类似。
所以的匹配模式都是绝对路径,也就是说所有的路径都是从根元素开始向下被指定的。但有一个例外,就是包含有通配符的"*"的匹配模式。如模式*/name将匹配XML文档中的任何<name>结点。还要注意一点,没有必要为根结点特殊做标记,因此所有的结点都是绝对的。
无认何时,当Digester遭遇到指定的匹配模式时,就会执行和这些模式相关的动作。从底层上来看,Digester框架是基于SAX分析器实现的(事实上,Digester类就实现了org.xml.sax.ContentHandler接口,并维护了相关的分析栈)。所有被Digester使用的规则(Rule)必须继承于org.apache.commons.digester.Rule,在这个类中提供了一些类似SAX的CantentHandler的回调方法。当打开和关闭XML结点时就会调用begin()和end()方法。
在匹配内容的过程中body()方法被调用,最后是finish()方法,这个方法在完成一次tag处理后调用,为了使开发工作更容易,大多数应用程序开发人员并不用关心这些方法的调用,而这一切都由Digester来为我们处理。
为了处理XML文档,我们需要建立一个org.apache.commons.digester.Digester类的实例,并配置它。如果必要,可以指定相关的模式和规则,最后,将XML文件的引用传入parse()方法。下面将给出一个DigesterDriver类,它将通过对上述的XML文档的处理来演示Digester的使用。XML文件将通过命令行方法传入程序。DigesterDriver的代码如下:
import org.apache.commons.digester.*; import java.io.*; import java.util.*; public class DigesterDriver { public static void main( String[] args ) { try { Digester digester = new Digester(); digester.setValidating( false ); digester.addObjectCreate( "catalog", Catalog.class ); digester.addObjectCreate( "catalog/book", Book.class ); digester.addBeanPropertySetter( "catalog/book/author", "author" ); digester.addBeanPropertySetter( "catalog/book/title", "title" ); digester.addSetNext( "catalog/book", "addBook" ); digester.addObjectCreate( "catalog/magazine", Magazine.class ); digester.addBeanPropertySetter( "catalog/magazine/name", "name" ); digester.addObjectCreate( "catalog/magazine/article", Article.class ); digester.addSetProperties( "catalog/magazine/article", "page", "page" ); digester.addBeanPropertySetter( "catalog/magazine/article/headline" ); digester.addSetNext( "catalog/magazine/article", "addArticle" ); digester.addSetNext( "catalog/magazine", "addMagazine" ); File input = new File( args[0] ); Catalog c = (Catalog)digester.parse( input ); System.out.println( c.toString() ); } catch( Exception exc ) { exc.printStackTrace(); } } }
在实例化Digester对象后。我们将不需要用DTD来验证我们的XML文档。这是因为在Catalog文档中并没有指定DTD。我们要做的只是指定模式和相关的规则。如首先使用addObjectCreate()方法将catalog结点和Catalog类绑定。如果XML的结点有属性的话,我们还可以通过的SetProperties方法将结点和Java类的属性对应起来。这个方法的第一个参数是XML结点属性名,第二个参数是类的属性名。
在上面代码中SetProperties方法仅仅是设置从一个属性取值,而SetBeanPropertySetter方法才真正将当前的结点和Java类对应。在使用setBeanPropertySetting方法时,并不一定要指写Java类的属性名,属性名在默认情况下和当前XML结点名相同。在上面的代码中,在设置catalog/magazine/article/headline模式时就使用了默认值。最后,我们使用addSetNext方法设置了分析栈的最顶层元素,也就是说article有多个,就象链表一样,一个接着一个排列。在本例子中使用了三次adSetNext方法来分别设置catalog/book、catalog/magazine/article和catalog/magazine。
要注意的是,我们可以为同一种模式注册更多的规则。如果我们这样做。这个规则将以它们被加入Digester的顺序来执行。例如,为了处理<article>元素,这个元素在catalog/magazine/article处被发现,我们首先会建立相应的Java类,然后设置page属性,最后弹出这个article类,并将其插入magzine结点。