帮助处理XML的工具很多,它们让我们活得更轻松。Jakarta Commons下的Digester就是一个不错的工具。它提供了一种将XML与Java对象进行映射的方便方法。这么说可能让新手更迷惑,还是举个例子吧!
我们有这样一个XML文件:
- <!-- Memos_2004-01-16.xml -->
- <?xml version="1.0"?>
- <memos>
- <memo>
- <title>About Jakatar commons Digester</title>
- <date>2004-01-16 02:05</date>
- <body>We are working on Digester 1.6-dev.Because it supported read
- attributes of element.We should pay attention to the releasing of
- Digester for its changing.</body>
- </memo>
- <memo>
- <title>Ah ha! Its good night!</title>
- <date>2004-01-16 4:19</date>
- <body>I has enhanced the basic framework of my app with improved
- architecture and performance. Its time to sleep. Good night,
- boys.</body>
- </memo>
- </memos>
这是我的备忘录,我用xml作为数据库。现在我们想用Java程序来读/写这个数据库应该怎么做呢?啊!对了,SAX、DOM……,好了,忘了它们吧!我们有更Easy的办法!
我们先来创建一个Memo类,它用来保存一条Memo。它有三个属性用来保存标题、日期以及Memo的正文。我们提供了公共的Setter和Getter,并且我们重载了toString()方法以便查看运行结果。
- /* Memo.java */
- package kitta.memo;
- public class Memo
- {
- /*-----/ Instance Field(s) /------------------------------------------------*/
- private String _title;
- private String _body;
- private String _date;
- /*-----/ Constructor(s) /---------------------------------------------------*/
- public Memo()
- {
- /* do nothing now */
- }
- /*-----/ Getter(s) & Setter(s) /--------------------------------------------*/
- public String getBody()
- {
- return _body;
- }
- public void setBody(String body)
- {
- _body = body;
- }
- public String getTitle()
- {
- return _title;
- }
- public void setTitle(String title)
- {
- _title = title;
- }
- public String getDate()
- {
- return _date;
- }
- public void setDate(String date)
- {
- _date = date;
- }
- /*-----/ Overrided Method(s) /----------------------------------------------*/
- public String toString()
- {
- StringBuffer buf = new StringBuffer();
- buf.append("\t").append(_title);
- buf.append("\tat\t").append(_date).append("\n\n");
- buf.append("\t").append(_body).append("\n");
- buf.append("-----------------------------------------------------------\n");
- return buf.toString();
- }
- }
然后是Memos类,它实际上是一个Memo对象的集合,完全可以用一个Collection的子类去代替它,但是这里之所以还是使用它主要是为了概念上的清晰。它同样很简单,一个私有属性_memos用来保存所有Memo对象的实例,一个共有方法addMemo()用来添加Memo,toString()方法的目的同上。
- /* Memos.java */
- package kitta.memo;
- import java.util.Collection;
- import java.util.Iterator;
- import java.util.Vector;
- public class Memos
- {
- /*-----/ Instance Fields /--------------------------------------------------*/
- private Collection _memos=new Vector();
- /*-----/ Constructor(s) /---------------------------------------------------*/
- public Memos()
- {
- /* do nothing */
- }
- /*-----/ Getter(s) & Setter(s) /--------------------------------------------*/
- public void addMemo(Memo memo)
- {
- _memos.add(memo);
- }
- /*-----/ Overrided Method(s) /----------------------------------------------*/
- public String toString()
- {
- StringBuffer buf = new StringBuffer();
- buf.append("-----------------------------------------------------------\n");
- buf.append(" Memo Application\n");
- buf.append(" (").append(_memos.size()).append(" memos total found.)\n");
- buf.append("-----------------------------------------------------------\n");
- for(Iterator itr = _memos.iterator();itr.hasNext();)
- {
- Memo m = (Memo) itr.next();
- buf.append(m.toString());
- }
- return buf.toString();
- }
- }
请注意init方法,它告诉Digester如何将XML中的数据映射到我们的Java对象。
- package kitta.memo;
- import java.io.IOException;
- import java.io.InputStream;
- import org.apache.commons.digester.Digester;
- public class MemoApp
- {
- /*-----/ Instance Field(s) /------------------------------------------------*/
- private Memos _memos;
- /*-----/ Constructor(s) /---------------------------------------------------*/
- public MemoApp()
- {
- /* do nothing */
- }
- /*-----/ Private Methods(s) /-----------------------------------------------*/
- /**
- * Initializes the instance of Digester.
- */
- private void init(Digester dgstr)
- {
- /* 当遇到memos元素时创建一个Memos对象 */
- dgstr.addObjectCreate("memos", Memos.class);
- /* 当遇到memo元素时创建一个Memo对象 */
- dgstr.addObjectCreate("memos/memo", Memo.class);
- /* 当遇到memos/memo/title元素时,调用当前Memo对象的setTitle方法 */
- dgstr.addBeanPropertySetter("memos/memo/title", "title");
- /* 当遇到memos/memo/body元素时,调用当前Memo对象的setBody */
- dgstr.addBeanPropertySetter("memos/memo/body", "body");
- /* 当遇到memos/memo/date元素时,调用当前Memo对象的setDate方法 */
- dgstr.addBeanPropertySetter("memos/memo/date", "date");
- /* 调用当前的Memos对象的addMemo方法,参数为当前的Memo对象 */
- dgstr.addSetNext("memos/memo", "addMemo");
- }
- /**
- * prints details of memos to standard out.
- */
- private void print()
- {
- System.out.println(_memos);
- }
- /**
- * maps the xml data to java object
- */
- private void load(InputStream in) throws Exception
- {
- Digester dgstr = new Digester();
- init(dgstr);
- try
- {
- _memos = (Memos) dgstr.parse(in);
- } catch (IOException e)
- {
- throw new Exception("Error occured When loading data",e);
- }
- }
- /*-----/ Main Method /------------------------------------------------------*/
- public static void main(String[] args) throws Exception
- {
- MemoApp mapp = new MemoApp();
- /* load xml file from classpath */
- mapp.load(MemoApp.class.getResourceAsStream("/kitta/memo/memo.xml"));
- mapp.print();
- }
- }
Digester用"elem/elem/elem"的方式来匹配xml中的元素。这非常直观,实际上我们很早就开始使用类似的方式了。Digester将其称为Pattern。
Digester中还有一个重要的概念就是Rule。我们在init方法中所做的就是将Pattern和Rule关联起来。当Digester发现与我们所注册的Pattern匹配的xml元素时,就会调用我们注册时指定Rule来处理这个元素。
环境
以上代码的测试环境为Windows XP、JDK 1.4.2 03、Digester 1.5 Release。
相关资源
Degister官方资源
Web site: [url]http://jakarta.apache.org/commons/digester/index.html[/url]
CVS connection: scm:cvs:pserver:anoncvs@cvs.apache.org:/home/cvspublic:jakarta-commons/digester/
CVS Web View: [url]http://cvs.apache.org/viewcvs/jakarta-commons/digester/[/url]
一些其它地方的文章:
[url]http://www-106.ibm.com/developerworks/java/library/j-lucene/[/url]
[url]http://www.javaworld.com/javaworld/jw-10-2002/jw-1025-opensourceprofile.html[/url]
[url]http://www.onjava.com/pub/a/onjava/2002/10/23/digester.html[/url]
最后
好啦!就这么简单!因为这只是一些基本的应用,它可以帮助你了解Digester,毕竟这只是一个Getting Start吗!要更好的应用,就要更深入的研究。