一般用来读取xml文件的工具包有DOM、SAX和JDOM等,但用过的人都知道,它们属于比较底层的API,写起来代码量很大,而且如果修改了xml文件的格式,代码也要做大幅度的改动。而使用Apache Jakarta的Digester,解析XML文件非常方便且不需要过多的关心底层的具体解析过程。Digester本来仅仅是Jakarta Struts中的一个工具,用于处理struts-config.xml配置文件。显然,将XML文件转换成相应的Java对象是一项很通用的功能,这个工具理应具有更广泛的用途,所以很快它就在Jakarta Commons项目(用于提供可重用的Java组件库)中有了一席之地。Digester由"事件"驱动,通过调用预定义的规则操作对象栈,将XML文件转换为Java对象。
工作原理如下: Digester底层采用SAX(Simple API for XML)析XML文件,所以很自然的,对象转换由"事件"驱动,在遍历每个节点时,检查是否有匹配模式,如果有,则执行规则定义的操作,比如创建特定的Java对象,或调用特定对象的方法等。此处的XML元素根据匹配模式(matching pattern)识别,而相关操作由规则(rule)定义。
如下xml代码,右边是左边元素对应的匹配模式:
下面是存放地址及编码的xml文件viewcache.xml(片段):
下面介绍解析xml文件的代码
例子1:
此xml文件分3层结构,分别为:
<viewcache>节点其下包含1个<areas>节点
<areas>节点其下包含多个<area>节点
<area>节点,其下包含各种信息节点:如:<id> 、<name>等。
我们的操作目标是把area中的信息节点的内容提取出来。
把每个<arrea>看做为一个对象,<area>中信息节点的内容为对象中的元素。
设定一个类Area.java 其内容如下:
创建一个ViewCache类,用来保存解析后的所有对象:
创建一个类AreaDigester,对xml文件进行解析:
调用AreaDigester的digester方法,即可把解析后的所有地址对象,存放在ViewCache的list中。
例子2:
要解析的xml文件books.xml如下:
Library类如下:
Book类如下:
Chapter类如下:
解析xml的类如下:
1. public class MainTest {
2.
3. /**
4. * @param args
5. */
6. public static void main(String[] args) {
7. // 建立一个Digester对象
8. Digester digester = new Digester();
9. //指定它不要用DTD验证XML文档的合法性——这是因为我们没有为XML文档定义DTD
10. digester.setValidating(false);
11. // 从library标签开始解析,并新建一个Library对象做为根对象
12. digester.addObjectCreate("library", Library.class);
13. // 根据library标签属性值设置对象的属性,一次可以设置多个属性
14. digester.addSetProperties("library");
15. // 也可以用下面的方法,指定propertyName
16. // digester.addSetProperties("library", "name", "name");
17.
18. // -----第1层元素开始
19. digester.addObjectCreate("library/book", Book.class);
20. //digester.addSetProperties("library/book");
21. // 可以用以下三条语句代替
22. digester.addCallMethod("library/book", "setBookInfo", 2);
23. digester.addCallParam("library/book", 0, "title");
24. digester.addCallParam("library/book", 1, "author");
25. /**
26. * addCallParam(String rule, int paraIndex,String attributeName)
27. * 该方法与addCallMethod配合使用
28. * int paraIndex:表明需要填充的方法形参序号,从 0 开始,方法由addCallMethod指定
29. * String attributeName:指定标签属性名称
30. */
31.
32.
33. // -----第2层元素开始
34. digester.addObjectCreate("library/book/chapter", Chapter.class);
35. /** addBeanPropertySetter()是将子节点转换为对象的属性,这个方法还可以有第二个参数,当对象的属性名和子节点的名字不一样时用来指定对象的属性名
36. 该方法的作用及使用方法类似于addSetProperties,只不过它是用String rule规则所指定标签的值(而不是标签的属性)来调用对象的setter*/
37. digester.addBeanPropertySetter("library/book/chapter/no");
38. // digester.addBeanPropertySetter("library/book/chapter/no", "no");
39.
40. /** addCallMethod(String rule,String methodName, int paraNumber) 方法
41. * 同样是设置对象的属性,但是方式更加灵活,不需要对象具有setter
42. * 当paraNumber = 0时,可以单独使用(表明为标签的值来调用),不然需要配合addCallParam方法
43. */
44. // digester.addBeanPropertySetter("library/book/chapter/caption");
45. // 下面的方法,可以用来代替上一句,作用是一样的
46. digester.addCallMethod("library/book/chapter/caption", "setCaption", 0);
47.
48. // addSetNext()是说在再次遇到匹配节点后, 调用当前对象(Chapter类的对象)的父对象(Book类的对象)的方法,方法参数是当前层元素的对象
49. digester.addSetNext("library/book/chapter", "addChapter");
50. // -----第2层元素结束
51.
52. digester.addSetNext("library/book", "addBook");
53. // -----第1层元素结束
54.
55. try {
56. // 解析XML文件,并得到ROOT元素
57. Library library = (Library) digester.parse(MainTest.class.getResourceAsStream("books.xml"));
58. System.out.println(" 图书馆: " + library.getName());
59. System.out.println(" 共藏书: " + library.getBookList().size() + " 本 ");
60. System.out.println(" ***************************** ");
61.
62. for (Book book : library.getBookList()) {
63. System.out.println(" 书名: " + book.getTitle() + " 作者: " + book.getAuthor());
64. System.out.println(" ------------------------------ ");
65. // 显示章节
66. System.out.println(" 共 " + book.getChapters().size() + " 章 ");
67. for (Chapter chapter : book.getChapters()) {
68. System.out.println(chapter.getNo() + ": " + chapter.getCaption());
69. }
70. System.out.println(" ------------------------------ ");
71. }
72. } catch (IOException e) {
73. e.printStackTrace();
74. } catch (SAXException e) {
75. e.printStackTrace();
76. }
77. }
78. }
Digester解析xml的规则,除了在java类中描述设置之外,还可以把解析规则放在xml文件中。以例子2中的代码为例,规则在books-rule.xml文件中,内容如下:(The DTD is distributed in the commons-digester.jar. It can be found at org/apache/commons/digester/xmlrules/digester-rules.dtd,通过查看DTD文件,可以知道有哪些标签可以使用)
1. <?xml version="1.0" encoding="UTF-8" ?>
2. <!DOCTYPE digester-rules PUBLIC
3. "-//Jakarta Apache //DTD digester-rules XML V1.0//EN"
4. "digester-rules.dtd">
5. <digester-rules>
6. <object-create-rule pattern="library" classname="com.alibaba.chj.digester.Library" />
7. <set-properties-rule pattern="library">
8. <alias attr-name="name" prop-name="name" />
9. </set-properties-rule>
10. <pattern value="library/book">
11. <object-create-rule classname="com.alibaba.chj.digester.Book" />
12. <set-properties-rule />
13. <pattern value="chapter">
14. <object-create-rule classname="com.alibaba.chj.digester.Chapter" />
15. <bean-property-setter-rule pattern="no" propertyname="no" />
16. <bean-property-setter-rule pattern="caption" propertyname="caption" />
17. <set-next-rule methodname="addChapter" />
18. </pattern>
19. <set-next-rule methodname="addBook" />
20. </pattern>
21. </digester-rules>
解析xml类的代码,修改为:
1. public class MainTest {
2.
3. /**
4. * @param args
5. */
6. public static void main(String[] args) {
7. try {
8. Digester digester = DigesterLoader.createDigester(DigesterXmlRuleTest.class.getResource("books-rule.xml"));
9. Library library = (Library) digester.parse(DigesterXmlRuleTest.class.getResourceAsStream("books.xml"));
10. System.out.println(" 图书馆: " + library.getName());
11. System.out.println(" 共藏书: " + library.getBookList().size() + " 本 ");
12. System.out.println(" ***************************** ");
13.
14. for (Book book : library.getBookList()) {
15. System.out.println(" 书名: " + book.getTitle() + " 作者: " + book.getAuthor());
16. System.out.println(" ------------------------------ ");
17. // 显示章节
18. System.out.println(" 共 " + book.getChapters().size() + " 章 ");
19. for (Chapter chapter : book.getChapters()) {
20. System.out.println(chapter.getNo() + ": " + chapter.getCaption());
21. }
22. System.out.println(" ------------------------------ ");
23. }
24. } catch (IOException e) {
25. e.printStackTrace();
26. } catch (SAXException e) {
27. e.printStackTrace();
28. }
29. }
30. }
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!