Digester学习笔记(二)

Digester学习笔记(二)

  为便于理解,将笔记的内容结构作了一些调整。

对象栈

  对digester技术最普通的应用,是用来动态创建一个由Java对象构成的树结构,各对象的属性以及对象间的关系,基于XML文档的内容来设置(XML文档就是一棵树)。为实现这种应用,Digester提供了一个对象栈,以供在相关的模板识别后被激活的处理规则操作。此栈的基本操作包括:

clear(),清空栈的内容 peek(),返回对栈顶对象的引用 pop(),将栈顶对象弹出并返回 push(),将一个新的对象压入栈顶


  用栈的原因,就是当识别出一个XML元素的“开始”时,将相关对象生成并压入栈顶,这个对象在处理该元素的子元素的过程中一直在栈中,当所有子元素都处理完后,解析器遇到这个元素的“结束”时,则弹出此对象,并进行相关的处理。
  如何描述对象间的关系呢?将栈顶的对象做为一个参数,传递给第二栈顶(即先于栈顶对象入栈的那个对象,在栈顶对象的下面)的一个方法,就可以简单地建立起一种“父子关系”,从而可以简单地建立起1:1的关系(第二栈顶对象与栈顶对象之间)和1:N的关系(第二栈顶对象不动,N次压栈顶弹栈顶对象).
  如果取得生成的第一个对象呢?可以让parse()方法返回,或者在调用parse()方法前,先行压入一个对象,在parse()方法结束后弹出这个对象,则其子对象即为我们想要的第一个对象。

日志(logging)


  日志是一个调试Digester规则集的非常重要的工具,它可以记录非常丰富的信息,因它在使用Digester之前有必要了解日志是如何工作的。
  Digester使用Jakarta Commons Logging,这个模块并不是具体的日志实现,而只是一个可设置的接口。可以设置它将各种日志信息传递它自身带的基本记录器,或者传递给其它的更复杂的日志工具。具体请参考commons logging的文档,或Jakarta Commons Logging学习笔记
  Digester主要使用两个记录器:

  1. SAX相关的信息,被送往org.apache.commons.digester.Digester.sax记录器,记录了Digester收到的SAX的事件的信息。
  2. 其它的所有信息,都被送往org.apache.commons.digester.Digester记录器,这个记录器在调试Digester时打开而在产品中常将其关闭


  假定用commons logging自带的基本日志工具,并以DEBUG级别记录Digester调试信息以及INFO级别记录SAX事件信息,则对logging的配置文件设置如下:

org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog org.apache.commons.logging.simplelog.log.org.apache.commons.digester.Digester=debug org.apache.commons.logging.simplelog.log.org.apache.commons.digester.Digester.sax=info

Digester包中的例子
***********Example.xml**********
<address-book>
<personid="1"category="acquaintance"try="wouldbeignored">
<name>Gonzo</name>
<emailtype="business">gonzo@muppets.com</email>
<genderresult="thewholetagwouldbeignored">male</gender>
</person>
<personid="2"category="rolemodel">
<name>Kermit</name>
<emailtype="business">kermit@muppets.com</email>
<emailtype="home">kermie@acme.com</email>
</person>
</address-book>**********Person.java************
importjava.util.HashMap;
importjava.util.Iterator;
publicclassPerson{
privateintid;
privateStringcategory;
privateStringname;
privateHashMapemails=newHashMap();
//下面的两个方法的名字中set以后的部分,与<person>的属性名字对映。当从xml文件中识别出<person>的属性时,如果有要求(即调用过addSetProperties方法),Digester会依据这种对映关系自动调用相应的方法。
publicvoidsetId(intid){
this.id=id;
}
publicvoidsetCategory(Stringcategory){
this.category=category;
}
//对name而言,因为其值来自<name>标签的内容而非属性值,需要用addCallMethod指定识别<name>后的要调用此方法(想自动调用也要可以,需要addBeanPropertySetter,参见第下一个例子)。
publicvoidsetName(Stringname){
this.name=name;
}
//同name,此时还要一一指定addEmail的参数值的来源。
publicvoidaddEmail(Stringtype,Stringaddress){
emails.put(type,address);
}
publicvoidprint(){
System.out.println("Person#"+id);
System.out.println("category="+category);
System.out.println("name="+name);
for(Iteratori=emails.keySet().iterator();i.hasNext();){
Stringtype=(String)i.next();
Stringaddress=(String)emails.get(type);
System.out.println("email(type"+type+"):"+address);
}
}
}
**********AddressBook.java***********
importjava.util.LinkedList;
importjava.util.Iterator;
publicclassAddressBook{
LinkedListpeople=newLinkedList();
publicvoidaddPerson(Personp){
people.addLast(p);
}
publicvoidprint(){
System.out.println("Addressbookhas"+people.size()+"entries");

for(Iteratori=people.iterator();i.hasNext();){
Personp=(Person)i.next();
p.print();
}
}
}
************AddressBookDigester*********
importorg.apache.commons.digester.Digester;
/**
*Usage:javaExample1example.xml
*/
publicclassAddressBookDigester{
publicstaticvoidmain(String[]args){
if(args.length!=1){
usage();
System.exit(-1);
}
Stringfilename=args[0];
//创建一个Digester实例
Digesterd=newDigester();
//创建AddressBook实例,并将其压入栈顶。
AddressBookbook=newAddressBook();
d.push(book);
//增加规则
addRules(d);
//处理输入的xml文件
try{
java.io.Filesrcfile=newjava.io.File(filename);
d.parse(srcfile);
}
catch(java.io.IOExceptionioe){
System.out.println("Errorreadinginputfile:"+ioe.getMessage());
System.exit(-1);
}
catch(org.xml.sax.SAXExceptionse){
System.out.println("Errorparsinginputfile:"+se.getMessage());
System.exit(-1);
}


//将解析出的地址数据打印出来
book.print();
}

privatestaticvoidaddRules(Digesterd){
//当遇到<person>时,创建类Person的一个实例,并将其压入栈顶
d.addObjectCreate("address-book/person",Person.class);

//将<person>标签的属性(attribute)与栈顶Person类对象的属性(property)设置方法根据各自的名字进行映射,(例如,将标签属性id与属性设置方法setId进行映射,将标签属性category与属性设置方法setCategory进行映射),然后将属性的值作参数传递给执行相应的方法。
//如果某标签属性没法通过名字找到相应的属性设置方法,则此标签属性被忽略(如example.xml中第一个<person>的try属性)。
d.addSetProperties("address-book/person");

//调用第二栈顶对象(AddressBook实例)的addPerson方法,以栈对象(Person实例)的对象为参数
d.addSetNext("address-book/person","addPerson");

//当遇到<person>的子元素<name>时,调用栈顶对象(Person实例)的setName方法。
//此处addCallMethod方法的第一参数是规则,第二个参数是方法的名字,第三个是参数的数量(为0时,表示只有一个参数,且参数的值是元素的内容)
d.addCallMethod("address-book/person/name","setName",0);

//当遇到<person>的子元素<email>时,调用栈顶对象(Person实例)的addEmail方法,addEmail方法有两个参数,取值分别来自<email>的属性type的值和<email>本身的内容。
//此处addCallParam方法的第一参数是规则,第二个参数是指明被调用方法(addEmail)参数的序号,第三个是参数为字符串时指属性的名字)
d.addCallMethod("address-book/person/email","addEmail",2);
d.addCallParam("address-book/person/email",0,"type");
d.addCallParam("address-book/person/email",1);
}

privatestaticvoidusage(){
System.out.println("Usage:javaExample1example.xml");
}
}

运行结果如下(运行时可能需要xml-crimson,一个源sun的XML解析器,可到http://xml.apache.org/crimson/下载)

Addressbookhas2entries
Person#1
category=acquaintance
name=Gonzo
email(typebusiness):gonzo@muppets.com
Person#2
category=rolemodel
name=Kermit
email(typebusiness):kermit@muppets.com
email(typehome):kermie@acme.com

Posted by Hilton at October 26, 2003 11:46 PM |TrackBack

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值