解析xml的工具有很多种:dom,dom4j,sax, Digester底层是使用的sax
一、引用 jar包
- commons-digester.jar
- commons-beanutils-1.7.0.jar
- commons-logging-1.1.jar
二、要读取的xml
<?xml version="1.0" encoding="utf-8" ?>
<school>
<classes>
<grade className="classOne" teacher="小花老师">
<student>
<no>1</no>
<name>张三</name>
<age>24</age>
</student>
<student>
<no>2</no>
<name>李四</name>
<age>24</age>
</student>
<student>
<no>1</no>
<name>王五</name>
<age>24</age>
</student>
</grade>
</classes>
</school>
三、代码实现
1、思路:最终目的是要创建3个Student和一个grade对象,先写bean对象,解析的时候默认对象属性和xml里面的标签是对应 的,如果不一致需要显示的标明:digester.addBeanPropertySetter("school/classes/grade/student/no","id");
2、代码:
public class Student {
private int id ;
private String name;
private int age;
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", age=" + age + "]";
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class Grade {
private String className;
private String teacher;
private List<Student> Students = new ArrayList<Student>();
public void addStudent(Student student){
Students.add(student);
}
@Override
public String toString() {
return "Grade [className=" + className + ", teacher=" + teacher
+ ", Students=" + Students + "]";
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public List<Student> getStudents() {
return Students;
}
public void setStudents(List<Student> students) {
Students = students;
}
}
public class Digester1 {
private Grade grade;
private SystemConfig systemConfig;
public static void main(String[] args) {
Digester1 digester1 = new Digester1();
digester1.loadConfig();
System.out.println(digester1.grade);
System.out.println(digester1.systemConfig);
}
private Digester digester;
public void loadConfig(){
//1.建立一个digester对象
digester = new Digester();
//应该是预防此对象加载 多个
digester.setClassLoader(Thread.currentThread().getContextClassLoader());
//将当前对象入到栈底,做为基准对象,下面第一个addSetNext() 这里面反射用到是引对象的方法
digester.push(this);
//2、不用dtd验证xml文档的合法性,我们没有为xml文档定义dtd
digester.setValidating(false);
//3.1从school--classes-class
final String gradeXml = "school/classes/grade";
//4.1将className赋值给对象
digester.addObjectCreate(gradeXml, Grade.class);
digester.addSetProperties(gradeXml);
digester.addSetNext(gradeXml, "addGrade");//这里面调用的是上个节点的方法,也就是Digester的方法
//3、从school--classes--class--student
final String stuXml= "school/classes/grade/student";
digester.addObjectCreate(stuXml,Student.class);
//4、将no,name,age标签赋给对象
digester.addBeanPropertySetter(stuXml+"/no","id");//将no里面数据放到Student的id字段中
digester.addBeanPropertySetter(stuXml+"/name");
digester.addBeanPropertySetter(stuXml+"/age");
digester.addSetNext(stuXml, "addStudent"); //这里调用的是前面被实例化的类,也就是grade里面的方法
//5、解析xml文件
try {
digester.parse(new File("./config/test1.xml"));
} catch (IOException | SAXException e) {
e.printStackTrace();
}
}
public void addGrade(Grade grade){
this.grade = grade;
}
}
3、梳理
digester的使用方法已经在Digester1里面注释的很清楚了,
- digester解析出来的类是在哪里??
答:如果只是创建一个student对象时,可以使用:Student student = digester.parse(new File("./config/test1.xml"));
- addSetNext,这个的作用是什么?
答:如上有多个Student对象需要生成,就需要触发父结点一个方法来储存这些对象,student的父节点是Grade类,Grade创建的对象的父节点是school我这里没用使用,可以忽略,但是Grade对象怎么保存呢???
digester.push(this); 将当前对象压到栈底,创建第一个对象,会调用栈底里面addSetNext里面映射的方法来处理生成的对象
- 如果是生成配置对象的话,建议把键值对写到xml标签的属性中,只需要一句代码就会自动将属性里面的键值对入到对象中,digester.addSetProperties(gradeXml); 会解析className,teacher
- 下面是怎么将方法设置到对象中 引用 : https://blog.csdn.net/shang02/article/details/53258904
addCallMethod(String rule,String methodName,int paraNumber) 该方法同样设置对象的属性,但更加灵活,不需要对象具有setter 根据rule规则指定的属性,调用对象的methodName方法,paraNumber参数是表示方法需要的参数个数,当paraNumber=0时,可以单独使用,不然需要配合addCallParam方法 比如:digester.addCallMethod("database/user/userName","setUserName",0), 参数为xml当前值;无参方法:digester.addCallMethod( "pattern", "methodName" );. |
addCallParam(String rule,int paraIndex,String attributeName) 该方法与addCallMethod配合使用,根据rule指定的标签属性来调用方法 paraIndex表明需要填充的方法形参序号,从0开始,方法由addCallMethdo指定,attributeName指定标签属性名; |
使用注意事项: |
;