XML已经成为了我们开发过程中不可缺少的技术。我们可以用它来描述程序的配置,适配不同的数据格式,甚至作为数据库使用。
帮助处理XML的工具很多,它们让我们活得更轻松。Jakarta Commons下的Digester就是一个不错的工具。它提供了一种将XML与Java对象进行映射的方便方法。这么说可能让新手更迷惑,还是举个例子吧!
我们有这样一个XML文件:
  1. <!-- Memos_2004-01-16.xml -->
  2. <?xml version="1.0"?>
  3. <memos>
  4. <memo>
  5.     <title>About Jakatar commons Digester</title>
  6.     <date>2004-01-16 02:05</date>
  7.     <body>We are working on Digester 1.6-dev.Because it supported read
  8.          attributes of element.We should pay attention to the releasing of 
  9.          Digester for its changing.</body>
  10. </memo>
  11. <memo>
  12.     <title>Ah ha! Its good night!</title>
  13.     <date>2004-01-16 4:19</date>
  14.     <body>I has enhanced the basic framework of my app with improved 
  15.          architecture and performance. Its time to sleep. Good night, 
  16.          boys.</body>
  17. </memo>
  18. </memos>

这是我的备忘录,我用xml作为数据库。现在我们想用Java程序来读/写这个数据库应该怎么做呢?啊!对了,SAX、DOM……,好了,忘了它们吧!我们有更Easy的办法!
我们先来创建一个Memo类,它用来保存一条Memo。它有三个属性用来保存标题、日期以及Memo的正文。我们提供了公共的Setter和Getter,并且我们重载了toString()方法以便查看运行结果。
  1. /* Memo.java */
  2. package kitta.memo;
  3. public class Memo
  4. {
  5.     /*-----/ Instance Field(s) /------------------------------------------------*/
  6.     private String _title;
  7.     private String _body;
  8.     private String _date;
  9.     /*-----/ Constructor(s) /---------------------------------------------------*/
  10.     public Memo()
  11.     {
  12.         /* do nothing now */
  13.     }
  14.     /*-----/ Getter(s) & Setter(s) /--------------------------------------------*/
  15.     public String getBody()
  16.     {
  17.         return _body;
  18.     }
  19.     public void setBody(String body)
  20.     {
  21.         _body = body;
  22.     }
  23.     public String getTitle()
  24.     {
  25.         return _title;
  26.     }
  27.     public void setTitle(String title)
  28.     {
  29.         _title = title;
  30.     }
  31.     public String getDate()
  32.     {
  33.         return _date;
  34.     }
  35.     public void setDate(String date)
  36.     {
  37.         _date = date;
  38.     }
  39.   /*-----/ Overrided Method(s) /----------------------------------------------*/
  40.     public String toString()
  41.     {
  42.         StringBuffer buf = new StringBuffer();
  43.         buf.append("\t").append(_title);
  44.         buf.append("\tat\t").append(_date).append("\n\n");
  45.         buf.append("\t").append(_body).append("\n");
  46.         buf.append("-----------------------------------------------------------\n");
  47.         return buf.toString();
  48.     }
  49. }



然后是Memos类,它实际上是一个Memo对象的集合,完全可以用一个Collection的子类去代替它,但是这里之所以还是使用它主要是为了概念上的清晰。它同样很简单,一个私有属性_memos用来保存所有Memo对象的实例,一个共有方法addMemo()用来添加Memo,toString()方法的目的同上。
  1. /* Memos.java */
  2. package kitta.memo;
  3. import java.util.Collection;
  4. import java.util.Iterator;
  5. import java.util.Vector;
  6. public class Memos
  7. {
  8.   /*-----/ Instance Fields /--------------------------------------------------*/
  9.   private Collection _memos=new Vector();
  10.   /*-----/ Constructor(s) /---------------------------------------------------*/
  11.   public Memos()
  12.   {
  13.     /* do nothing */
  14.   }
  15.   /*-----/ Getter(s) & Setter(s) /--------------------------------------------*/
  16.   public void addMemo(Memo memo)
  17.   {
  18.     _memos.add(memo);
  19.   }
  20.   /*-----/ Overrided Method(s) /----------------------------------------------*/
  21.   public String toString()
  22.   {
  23.     StringBuffer buf = new StringBuffer();
  24.     buf.append("-----------------------------------------------------------\n");
  25.     buf.append("        Memo Application\n");
  26.     buf.append("    (").append(_memos.size()).append(" memos total found.)\n");
  27.     buf.append("-----------------------------------------------------------\n");
  28.   
  29.     for(Iterator itr = _memos.iterator();itr.hasNext();)
  30.     {
  31.       Memo m = (Memo) itr.next();
  32.       buf.append(m.toString());
  33.     }
  34.         return buf.toString();
  35.   }
  36. }



请注意init方法,它告诉Digester如何将XML中的数据映射到我们的Java对象。
  1. package kitta.memo;
  2. import java.io.IOException;
  3. import java.io.InputStream;
  4. import org.apache.commons.digester.Digester;
  5. public class MemoApp
  6. {
  7.   /*-----/ Instance Field(s) /------------------------------------------------*/
  8.   private    Memos _memos;
  9.   /*-----/ Constructor(s) /---------------------------------------------------*/
  10.     public MemoApp()
  11.     {
  12.         /* do nothing */
  13.     }
  14.   /*-----/ Private Methods(s) /-----------------------------------------------*/
  15.   /**
  16.    * Initializes the instance of Digester.
  17.    */
  18.     private void init(Digester dgstr)
  19.     {
  20.     /* 当遇到memos元素时创建一个Memos对象 */
  21.     dgstr.addObjectCreate("memos", Memos.class);
  22.     /* 当遇到memo元素时创建一个Memo对象 */
  23.     dgstr.addObjectCreate("memos/memo", Memo.class);
  24.     /* 当遇到memos/memo/title元素时,调用当前Memo对象的setTitle方法 */
  25.     dgstr.addBeanPropertySetter("memos/memo/title""title");
  26.     /* 当遇到memos/memo/body元素时,调用当前Memo对象的setBody */
  27.     dgstr.addBeanPropertySetter("memos/memo/body""body");
  28.     /* 当遇到memos/memo/date元素时,调用当前Memo对象的setDate方法 */
  29.     dgstr.addBeanPropertySetter("memos/memo/date""date");
  30.     /* 调用当前的Memos对象的addMemo方法,参数为当前的Memo对象 */
  31.     dgstr.addSetNext("memos/memo""addMemo");
  32.    
  33.     }
  34.   /**
  35.    * prints details of memos to standard out.
  36.    */
  37.   private void print()
  38.   {
  39.     System.out.println(_memos);
  40.   }
  41.   /**
  42.    * maps the xml data to java object
  43.    */  
  44.   private void load(InputStream in) throws Exception
  45.     {
  46.         Digester dgstr = new Digester();
  47.     init(dgstr);
  48.         try
  49.         {
  50.             _memos = (Memos) dgstr.parse(in);
  51.         } catch (IOException e)
  52.         {
  53.       throw new Exception("Error occured When loading data",e);
  54.         }
  55.     }
  56.   /*-----/ Main Method /------------------------------------------------------*/
  57.   public static void main(String[] args) throws Exception
  58.     {
  59.         MemoApp mapp = new MemoApp();
  60.     /* load xml file from classpath */
  61.     mapp.load(MemoApp.class.getResourceAsStream("/kitta/memo/memo.xml"));
  62.     mapp.print();
  63.     }
  64. }



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吗!要更好的应用,就要更深入的研究。