在我们的项目中或多或少会采用xml来做配置文件,你可以采用Java原生支持的sax、DOM或者第三方的dom4j等。虽然提供了各式各样的解析方式,但是解析一个复杂的xml所编写的Java代码是非常麻烦的,尤其是当xml做了修改,你会发现你又要修改Java代码。
Apache的commons项目中Digester项目解决了这个问题,它可以很轻易地将xml文件解析成Java对象,让你直接去使用,而你仅仅需要去预定义一份解析规则。
而对于解析规则,你可以采用Java的方式定义、xml的方式定义亦或者annotation的方式定义。
要使用digester需要引入依赖:
<!--apache commons digester--> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-digester3</artifactId> <version>3.2</version> </dependency>
假设我们要解析如下school.xml文件
<?xml version="1.0" encoding="utf-8" ?> <school> <classes> <class className="classOne"> <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> </class> </classes> </school>
我们需要预定义Student、Class、School节点的Java类与之对应
package cn.lay.demo.digester.definition; /** * 学生节点 * @author lay * @date 2018/10/16 23:35 */ public class StudentDefinition { private Integer no; private String name; private Integer age; public Integer getNo() { return no; } public void setNo(Integer no) { this.no = no; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "StudentDefinition{" + "no=" + no + ", name='" + name + '\'' + ", age=" + age + '}'; } } package cn.lay.demo.digester.definition; import java.util.ArrayList; import java.util.List; /** * 班级节点 * @author lay * @date 2018/10/16 23:36 */ public class ClassDefinition { private String className; private List<StudentDefinition> studentDefinitionList = new ArrayList<>(); public String getClassName() { return className; } public void setClassName(String className) { this.className = className; } public List<StudentDefinition> getStudentDefinitionList() { return studentDefinitionList; } public void setStudentDefinitionList(List<StudentDefinition> studentDefinitionList) { this.studentDefinitionList = studentDefinitionList; } public void addStudent(StudentDefinition studentDefinition) { studentDefinitionList.add(studentDefinition); } @Override public String toString() { return "ClassDefinition{" + "className='" + className + '\'' + ", studentDefinitionList=" + studentDefinitionList + '}'; } } package cn.lay.demo.digester.definition; import java.util.ArrayList; import java.util.List; /** * 学校节点 * @author lay * @date 2018/10/16 23:37 */ public class SchoolDefinition { private List<ClassDefinition> classDefinitions = new ArrayList<>(); public List<ClassDefinition> getClassDefinitions() { return classDefinitions; } public void setClassDefinitions(List<ClassDefinition> classDefinitions) { this.classDefinitions = classDefinitions; } public void addClass(ClassDefinition classDefinition) { classDefinitions.add(classDefinition); } @Override public String toString() { return "SchoolDefinition{" + "classDefinitions=" + classDefinitions + '}'; } }
1、Java方式配置解析规则
rule
package cn.lay.demo.digester.rule; import cn.lay.demo.digester.definition.ClassDefinition; import cn.lay.demo.digester.definition.SchoolDefinition; import cn.lay.demo.digester.definition.StudentDefinition; import org.apache.commons.digester3.Digester; import java.net.URL; /** * java方式定义解析规则 * @author lay * @date 2018/10/16 23:38 */ public class DigesterRule { /** * 解析 * @param filePath * @return */ public SchoolDefinition execute(String filePath) throws Exception{ Digester digester = new Digester(); digester.setValidating(false); // classes node digester.addObjectCreate("school/classes", SchoolDefinition.class); // class node digester.addObjectCreate("school/classes/class", ClassDefinition.class); // set properties digester.addSetProperties("school/classes/class"); // student node digester.addObjectCreate("school/classes/class/student", StudentDefinition.class); // set properties digester.addBeanPropertySetter("school/classes/class/student/no"); digester.addBeanPropertySetter("school/classes/class/student/name"); digester.addBeanPropertySetter("school/classes/class/student/age"); // add student digester.addSetNext("school/classes/class/student", "addStudent"); // add class digester.addSetNext("school/classes/class", "addClass"); // parse URL url = this.getClass().getClassLoader().getResource(filePath); System.out.println("url=" + url.toString()); return digester.parse(url); } }
测试
@Test public void testJavaRule() throws Exception { SchoolDefinition schoolDefinition = new DigesterRule().execute("school.xml"); System.out.println(schoolDefinition); }
2、xml方式配置解析规则
rule
<!DOCTYPE digester-rules PUBLIC "-//Apache Commons //DTD digester-rules XML V1.0//EN" "http://commons.apache.org/digester/dtds/digester-rules-3.0.dtd"> <digester-rules> <!--school node--> <pattern value="school/classes"> <object-create-rule classname="cn.lay.demo.digester.definition.SchoolDefinition"/> <!--class node--> <pattern value="class"> <object-create-rule classname="cn.lay.demo.digester.definition.ClassDefinition"/> <set-properties-rule/> <!--student node--> <pattern value="student"> <object-create-rule classname="cn.lay.demo.digester.definition.StudentDefinition"/> <bean-property-setter-rule pattern="no"/> <bean-property-setter-rule pattern="name"/> <bean-property-setter-rule pattern="age"/> <set-next-rule methodname="addStudent"/> </pattern> <set-next-rule methodname="addClass"/> </pattern> </pattern> </digester-rules>
测试
@Test public void testXmlRule() throws Exception { Digester digester = DigesterLoader.newLoader(new XmlRulesModule()).newDigester(); URL url = this.getClass().getClassLoader().getResource("school.xml"); System.out.println("url=" + url); SchoolDefinition schoolDefinition = digester.parse(url); System.out.println(schoolDefinition); } class XmlRulesModule extends FromXmlRulesModule { @Override protected void loadRules() { loadXMLRules(this.getClass().getClassLoader().getResourceAsStream("rule/schoolRule.xml")); } }
3、注解方式配置解析规则
基于零配置思想,digester支持采用annotation来注解相应的解析规则。
rule
package cn.lay.demo.digester.definition; import org.apache.commons.digester3.annotations.rules.ObjectCreate; import org.apache.commons.digester3.annotations.rules.SetNext; import org.apache.commons.digester3.annotations.rules.SetRoot; import java.util.ArrayList; import java.util.List; /** * 学校节点 * @author lay * @date 2018/10/16 23:37 */ @ObjectCreate(pattern = "school/classes") public class SchoolDefinition { private List<ClassDefinition> classDefinitions = new ArrayList<>(); public List<ClassDefinition> getClassDefinitions() { return classDefinitions; } public void setClassDefinitions(List<ClassDefinition> classDefinitions) { this.classDefinitions = classDefinitions; } @SetNext public void addClass(ClassDefinition classDefinition) { System.out.println("执行了addClass"); classDefinitions.add(classDefinition); } @Override public String toString() { return "SchoolDefinition{" + "classDefinitions=" + classDefinitions + '}'; } } package cn.lay.demo.digester.definition; import org.apache.commons.digester3.annotations.rules.*; import java.util.ArrayList; import java.util.List; /** * 班级节点 * @author lay * @date 2018/10/16 23:36 */ @ObjectCreate(pattern = "school/classes/class") public class ClassDefinition { @SetProperty(pattern = "school/classes/class") private String className; private List<StudentDefinition> studentDefinitionList = new ArrayList<>(); public String getClassName() { return className; } public void setClassName(String className) { this.className = className; } public List<StudentDefinition> getStudentDefinitionList() { return studentDefinitionList; } public void setStudentDefinitionList(List<StudentDefinition> studentDefinitionList) { this.studentDefinitionList = studentDefinitionList; } @SetNext public void addStudent(StudentDefinition studentDefinition) { System.out.println("执行了addStudent"); studentDefinitionList.add(studentDefinition); } @Override public String toString() { return "ClassDefinition{" + "className='" + className + '\'' + ", studentDefinitionList=" + studentDefinitionList + '}'; } } package cn.lay.demo.digester.definition; import org.apache.commons.digester3.annotations.rules.BeanPropertySetter; import org.apache.commons.digester3.annotations.rules.ObjectCreate; /** * 学生节点 * @author lay * @date 2018/10/16 23:35 */ @ObjectCreate(pattern = "school/classes/class/student") public class StudentDefinition { @BeanPropertySetter(pattern = "school/classes/class/student/no") private Integer no; @BeanPropertySetter(pattern = "school/classes/class/student/name") private String name; @BeanPropertySetter(pattern = "school/classes/class/student/age") private Integer age; public Integer getNo() { return no; } public void setNo(Integer no) { this.no = no; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "StudentDefinition{" + "no=" + no + ", name='" + name + '\'' + ", age=" + age + '}'; } }
测试
@Test public void testAnnotationRule() throws Exception { Digester digester = DigesterLoader.newLoader(new FromAnnotationsRuleModule() { @Override protected void configureRules() { // 这里只添加SchoolDefinition即可 bindRulesFrom(SchoolDefinition.class); } }).newDigester(); URL url = this.getClass().getClassLoader().getResource("school.xml"); System.out.println("url=" + url); SchoolDefinition schoolDefinition = digester.parse(url); System.out.println(schoolDefinition); }