存档: 标签: ‘Digester’

Commons-Digester read xml to JavaBean

没有评论 2010年4月17日

最近在做一个小项目,需要读取数据字典XML中的内容取出相应的配置信息,在前台用Extjs生成一个查询框架,刚开始我是自己利用dom的开源lib以SAX的方式读数据字典,生成相应的java对象,但总感觉自己写的读取方法不是很完美,所以想在网上找找更好的解决办法。百度一下,看到了 Commons-Digester这个开源的jar文件,Digester本来仅仅是Jakarta Struts中的一个工具,用于处理struts-config.xml配置文件,后来就独立出来用于解析XML文件。

Digester由”事件”驱动,通过调用预定义的规则操作对象栈,将XML文件转换为Java对象。工作原理如下:
Digester底层采用SAX解析XML文件,所以很自然的,对象转换由”事件”驱动,即在识别出特定XML元素时(实际被细分为begin、 body、end、finish四个时点),将执行特定的动作,比如创建特定的Java对象,或调用特定对象的方法等。此处的XML元素根据匹配模式 (matching pattern)识别,而相关操作由规则(rule)定义。在转换过程中,Digester维持了一个对象栈,可以看作对象转换的工作台,用来存放转换中生成的、或是为转换临时创建的Java对象。对输入XML文件作了一趟完整的扫描后,对象栈的栈顶元素即为目标对象。由于Digester屏蔽了SAX解析的细节,使用者仅需关注转换操作本身,大大简化了转换操作。

使用Digester,基本步骤如下:
1.创建Digester对象实例。
2.设置该Digester对象的配置属性(可选)。
3.将需要的初始对象 push到该Digester对象的对象栈上(可选)。
4.需要注册所有的XML元素匹配模式与处理规则之间的映射关系。
5.用 digester.parse()解析的XML文档对象,得到目标对象。

在了解了Digester的实现原理和解析方式,就寻找网上现成的例子,自己在电脑上实现了一遍,由于网上的例子大多都不详细,所以在测试的过程中不断出现一些异常,但又不知道问题出自哪里、如何解决 :cry:
最后终于找到了一个比较详细的实例,呵呵
以下是一个测试方法,其它的代码没有贴出,如有需要可以告诉我:

package com.javachen.xml.digester;

import java.io.File;
import java.io.IOException;
import org.junit.Test;
import org.xml.sax.SAXException;

import org.apache.commons.digester.Digester;

import static org.junit.Assert.*;

public class DigesterTest {

	/**
	 * 属性方式
	 */
	@Test
	public void testOne() {
		Digester digester = new Digester();
		// 设置不进行合法性验证
		digester.setValidating(false);
		// 当遇到<teacher>时创建一个Teacher对象,放入栈顶
		digester.addObjectCreate("teacher", Teacher.class);
		digester.addSetProperties("teacher");
		// 当遇到<teacher>的子元素<student>时创建一个Student对象,放入栈顶
		digester.addObjectCreate("teacher/student", Student.class);
		// 设置<student>的属性值,根据属性值调用相应的set方法
		digester.addSetProperties("teacher/student");
		// 当再次遇到<student>时创建一个Student对象,放入栈顶,
                //同时调用栈次顶的addStudent方法
		digester.addSetNext("teacher/student", "addStudent",
				"com.javachen.xml.digester.Student");
		try {
			Teacher teacher = (Teacher) digester.parse(new File(
					"src/com/javachen/xml/digester/student.xml"));
			assertEquals(8, teacher.getStudents().size());
		} catch (IOException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 子标签方式(设置Property方式一)
	 */
	@Test
	public void testTwo() {
		Digester digester = new Digester();
		digester.setValidating(false);
		// 设置栈顶
		digester.push(new TeacherList());
		digester.addObjectCreate("teachers/teacher", Teacher.class);
		digester.addSetProperties("teachers/teacher");
		digester.addObjectCreate("teachers/teacher/student", Student.class);
//		digester.addSetProperties("teachers/teacher/student");
		// 子标签方式设置属性方法之一,第三个参数是第二个参数所指方法的参数个数
		digester.addCallMethod("teachers/teacher/student/name", "setName", 1);
		digester.addCallMethod("teachers/teacher/student/age", "setAge", 1);
		digester.addCallMethod("teachers/teacher/student/id", "setId", 1);
		digester.addSetNext("teachers/teacher/student", "addStudent",
				"com.javachen.xml.digester.Student");
		digester.addSetNext("teachers/teacher", "addTeachers",
				"com.javachen.xml.digester.Teacher");
		try {
			TeacherList teacher = (TeacherList) digester.parse(new File(
					"src/com/javachen/xml/digester/teacher.xml"));
			assertEquals(2, teacher.getTeachers().size());
			assertEquals("java", teacher.getTeachers().get(0).getCourse());
			assertEquals(8, teacher.getTeachers().get(0).getStudents().size());
		} catch (IOException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 子标签方式(设置Property方式二)
	 */
	@Test
	public void testThree() {
		Digester digester = new Digester();
		digester.setValidating(false);
		// 设置栈顶
		digester.push(new TeacherList());
		digester.addObjectCreate("teachers/teacher", Teacher.class);
		digester.addSetProperties("teachers/teacher");
		digester.addObjectCreate("teachers/teacher/student", Student.class);
		// 子标签方式设置属性方法之二
		digester.addBeanPropertySetter("teachers/teacher/student/name");
		digester.addBeanPropertySetter("teachers/teacher/student/age");
		digester.addBeanPropertySetter("teachers/teacher/student/id");
		digester.addSetNext("teachers/teacher/student", "addStudent",
				"com.javachen.xml.digester.Student");
		digester.addSetNext("teachers/teacher", "addTeachers",
				"com.javachen.xml.digester.Teacher");
		try {

			TeacherList teacher = (TeacherList) digester.parse(new File(
					"src/com/javachen/xml/digester/teacher.xml"));
			assertEquals(2, teacher.getTeachers().size());
			assertEquals("java", teacher.getTeachers().get(0).getCourse());
			assertEquals(8, teacher.getTeachers().get(0).getStudents().size());
		} catch (IOException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 子标签方式 (callMethod callParam方式)
	 */
	@Test
	public void testFour() {
		Digester digester = new Digester();
		digester.setValidating(false);
		digester.push(new TeacherList());
		digester.addObjectCreate("teachers/teacher", "com.javachen.xml.digester.Teacher");
		digester.addSetProperties("teachers/teacher");
		// 当<student>时调用栈顶元素(Teacher)的addStudents却并不执行,
               //等待addCallParam设置参数,3为参数个数,这里传入的参数是字符串。
		digester.addCallMethod("teachers/teacher/student", "addStudent", 3);
		digester.addCallParam("teachers/teacher/student/name", 0);
		digester.addCallParam("teachers/teacher/student/age", 1);
		// 这句之后即</student>才调用addStudents方法,并且如果再次遇到<student>重复。
		digester.addCallParam("teachers/teacher/student/id", 2);
		digester.addSetNext("teachers/teacher", "addTeachers",
				"com.javachen.xml.digester.Teacher");
		try {
			TeacherList teacher = (TeacherList) digester.parse(new File(
					"src/com/javachen/xml/digester/teacher.xml"));
			assertEquals(2, teacher.getTeachers().size());
			assertEquals("java", teacher.getTeachers().get(0).getCourse());
			assertEquals(8, teacher.getTeachers().get(0).getStudents().size());
			assertEquals("李世民2", teacher.getTeachers().get(1).getStudents()
					.get(2).getName());
		} catch (IOException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		}
	}
}