XML已经成为了我们开发过程中不可缺少的技术。我们可以用它来描述程序的配置,适配不同的数据格式,甚至作为数据库使用。
帮助处理XML的工具很多,它们让我们活得更轻松。Jakarta Commons下的Digester就是一个不错的工具。它提供了一种将XML与Java对象进行映射的方便方法。这么说可能让新手更迷惑,还是举个例子吧!
我们有这样一个XML文件:
1.
2. <!-- Memos_2004-01-16.xml -->
3. <?xml version="1.0"?>
4. <memos>
5. <memo>
6. <title>About Jakatar commons Digester</title>
7. <date>2004-01-16 02:05</date>
8. <body>We are working on Digester 1.6-dev.Because it supported read
9. attributes of element.We should pay attention to the releasing of
10. Digester for its changing.</body>
11. </memo>
12.
13. <memo>
14. <title>Ah ha! It's good night!</title>
15. <date>2004-01-16 4:19</date>
16. <body>I has enhanced the basic framework of my app with improved
17. architecture and performance. It's time to sleep. Good night,
18. boys.</body>
19. </memo>
20. </memos>
这是我的备忘录,我用xml作为“数据库”。现在我们想用Java程序来读/写这个“数据库”应该怎么做呢?啊!对了,SAX、DOM……,好了,忘了它们吧!我们有更Easy的办法!
我们先来创建一个Memo类,它用来保存一条Memo。它有三个属性用来保存标题、日期以及Memo的正文。我们提供了公共的Setter和Getter,并且我们重载了toString()方法以便查看运行结果
1.
2. /* Memo.java */
3. package kitta.memo;
4.
1. public class Memo
2. {
3. /*-----/ Instance Field(s) /------------------------------------------------*/
4. private String _title;
5. private String _body;
6. private String _date;
7. /*-----/ Constructor(s) /---------------------------------------------------*/
8. public Memo()
9. {
10. /* do nothing now */
11. }
12.
13. /*-----/ Getter(s) & Setter(s) /--------------------------------------------*/
14. public String getBody()
15. {
16. return _body;
17. }
18.
19. public void setBody(String body)
20. {
21. _body = body;
22. }
23.
24. public String getTitle()
25. {
26. return _title;
27. }
28.
29. public void setTitle(String title)
30. {
31. _title = title;
32. }
33.
34. public String getDate()
35. {
36. return _date;
37. }
38. public void setDate(String date)
39. {
40. _date = date;
41. }
42. /*-----/ Overrided Method(s) /----------------------------------------------*/
43. public String toString()
44. {
45. StringBuffer buf = new StringBuffer();
46. buf.append("/t").append(_title);
47. buf.append("/tat/t").append(_date).append("/n/n");
48. buf.append("/t").append(_body).append("/n");
49. buf.append("-----------------------------------------------------------/n");
50. return buf.toString();
51. }
52. }
然后是Memos类,它实际上是一个Memo对象的集合,完全可以用一个Collection的子类去代替它,但是这里之所以还是使用它主要是为了概念上的清晰。它同样很简单,一个私有属性_memos用来保存所有Memo对象的实例,一个共有方法addMemo()用来添加Memo,toString()方法的目的同上。
1. /* Memos.java */
2. package kitta.memo;
3.
4. import java.util.Collection;
5. import java.util.Iterator;
6. import java.util.Vector;
7.
8.
9. public class Memos
10. {
11. /*-----/ Instance Fields /--------------------------------------------------*/
12. private Collection _memos=new Vector();
13. /*-----/ Constructor(s) /---------------------------------------------------*/
14. public Memos()
15. {
16. /* do nothing */
17. }
18. /*-----/ Getter(s) & Setter(s) /--------------------------------------------*/
19. public void addMemo(Memo memo)
20. {
21. _memos.add(memo);
22. }
23. /*-----/ Overrided Method(s) /----------------------------------------------*/
24. public String toString()
25. {
26. StringBuffer buf = new StringBuffer();
27. buf.append("-----------------------------------------------------------/n");
28. buf.append(" Memo Application/n");
29. buf.append(" (").append(_memos.size()).append(" memos total found.)/n");
30. buf.append("-----------------------------------------------------------/n");
31.
32. for(Iterator itr = _memos.iterator();itr.hasNext();)
33. {
34. Memo m = (Memo) itr.next();
35. buf.append(m.toString());
36. }
37. return buf.toString();
38. }
39. }
请注意init方法,它告诉Digester如何将XML中的数据映射到我们的Java对象。
1.
2. package kitta.memo;
3.
4. import java.io.IOException;
5. import java.io.InputStream;
6.
7. import org.apache.commons.digester.Digester;
8.
9. public class MemoApp
10. {
11. /*-----/ Instance Field(s) /------------------------------------------------*/
12. private Memos _memos;
13. /*-----/ Constructor(s) /---------------------------------------------------*/
14. public MemoApp()
15. {
16. /* do nothing */
17. }
18. /*-----/ Private Methods(s) /-----------------------------------------------*/
19. /**
20. * Initializes the instance of Digester.
21. */
22. private void init(Digester dgstr)
23. {
24. /* 当遇到memos元素时创建一个Memos对象 */
25. dgstr.addObjectCreate("memos", Memos.class);
26. /* 当遇到memo元素时创建一个Memo对象 */
27. dgstr.addObjectCreate("memos/memo", Memo.class);
28. /* 当遇到memos/memo/title元素时,调用当前Memo对象的setTitle方法 */
29. dgstr.addBeanPropertySetter("memos/memo/title", "title");
30. /* 当遇到memos/memo/body元素时,调用当前Memo对象的setBody */
31. dgstr.addBeanPropertySetter("memos/memo/body", "body");
32. /* 当遇到memos/memo/date元素时,调用当前Memo对象的setDate方法 */
33. dgstr.addBeanPropertySetter("memos/memo/date", "date");
34. /* 调用当前的Memos对象的addMemo方法,参数为当前的Memo对象 */
35. dgstr.addSetNext("memos/memo", "addMemo");
36.
37. }
38. /**
39. * prints details of memos to standard out.
40. */
41. private void print()
42. {
43. System.out.println(_memos);
44. }
45. /**
46. * maps the xml data to java object
47. */
48. private void load(InputStream in) throws Exception
49. {
50. Digester dgstr = new Digester();
51. init(dgstr);
52. try
53. {
54. _memos = (Memos) dgstr.parse(in);
55. } catch (IOException e)
56. {
57. throw new Exception("Error occured When loading data",e);
58. }
59. }
60. /*-----/ Main Method /------------------------------------------------------*/
61. public static void main(String[] args) throws Exception
62. {
63. MemoApp mapp = new MemoApp();
64. /* load xml file from classpath */
65. mapp.load(MemoApp.class.getResourceAsStream("/kitta/memo/memo.xml"));
66. mapp.print();
67. }
68. }
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: http://jakarta.apache.org/commons/digester/index.html
CVS connection: scm:cvs:pserver:[email protected]:/home/cvspublic:jakarta-commons/digester/
CVS Web View: http://cvs.apache.org/viewcvs/jakarta-commons/digester/