Digester 解析 XML 成 java 对象
惯例,提供参考连接, 高大全:http://www.massapi.com/class/di/Digester.html
api:http://commons.apache.org/proper/commons-digester/commons-digester-3.0/apidocs/
1. 其实现思路是基于XML元素节点读取事件驱动的,依赖SAX。使用W3C 的XPATH来监听xml元素节点的读取。
2. 简单例子
现有xml, test-members.xml:
<members> <member name="Oham" species="human"> <skill>create</skill> <equipment id="11" version="v1.0">Saurcer ship</equipment> <equipment id="12" version="v1.2-beta">Predator mask</equipment> <level>6</level> </member> <member name="Oham" species="dog"> <skill>know the truth</skill> <skill>free the soul</skill> <level>12</level> </member> </members>
构造java bean,以映射xml,这里构造两个bean,Members.java对应元素<members>;Member.java对应<member>。
Members.java:
package org.oham.xml; import java.util.ArrayList; import java.util.List; public class Members { private List<Member> members = new ArrayList<Member>(); public List<Member> getMembers() { return members; } public void addMember(Member member) { members.add(member); } }
Member.java:
package org.oham.xml; import java.util.HashSet; import java.util.Set; public class Member { private String name; private String species; private Set<String> skills = new HashSet<String>(); private Set<String> equipments = new HashSet<String>(); public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSpecies() { return species; } public void setSpecies(String species) { this.species = species; } public Set<String> getSkills() { return skills; } public Set<String> getEquipments() { return equipments; } public void addSkill(String skill) { this.skills.add(skill); } public void addEquipment(String equipment, int id, String version) { System.out.println("id: " + id + ", version: " + version + " stand by."); this.equipments.add(equipment); } }
使用Digester读取并解析xml,有几种种方式,介绍两种:
//使用方式一,调用Digester中的方法解析XPATH, public Members parse(File xmlFile) throws IOException, SAXException { System.out.println("parse XPATH with API method"); Digester digester = new Digester(); // 遇到members元素节点开始时,构造Members类的对象 digester.addObjectCreate("members", Members.class); // 遇到members元素的子元素member开始时,构造Member类的对象 digester.addObjectCreate("members/member", Member.class); // set up members元素的子元素member的属性值, 前提是xml中的属性名必须与java bean中的一致 // 并且java bean 要有对应的setter方法 digester.addSetProperties("members/member"); // 将当前members元素的子元素member所对应的bean 通过调用其parent members所对应的Members实例 // 中的方法 addMember,并以其所对应的bean作为参数传入,这样就可以在Members中初始化member的实例了 digester.addSetNext("members/member", "addMember"); // 遇到members元素的子元素member中的skill节点时调用其直接parent member实例中的addSkill方法 // 第三个参数为xml的参数索引,这里 0 表示去取skill元素body内的值,并且取出的只能是String类型(假如是数字,而addSkill中的参数为int类型,这样会抛No such accessible method exception, // 就是说默认只认识String类型的参数,改成String类型参数就能取到,看下面的level就知道) digester.addCallMethod("members/member/skill", "addSkill", 0); // 当需要参入不同类型的多个参数时,这样用 digester.addCallMethod("members/member/equipment", "addEquipment", 3, new String[]{"java.lang.String", "java.lang.Integer", "java.lang.String"}); // 标记equipment 元素 body中的值为参数一 digester.addCallParam("members/member/equipment", 0); // 标记equipment 元素 属性id的值为参数二 digester.addCallParam("members/member/equipment", 1, "id"); // 标记equipment 元素 属性version的值为参数三 digester.addCallParam("members/member/equipment", 2, "version"); // 抛No such accessible method: setLevel() on object: org.oham.xml.Member,setLevel中传入的是int类型参数,它不认 //digester.addCallMethod("members/member/level", "setLevel", 0); //解决1:调用CallParam标记参数 digester.addCallMethod("members/member/level", "setLevel", 1, new String[]{"java.lang.Integer"}); digester.addCallParam("members/member/level", 0); //解决2:调用addBeanPropertySetter,去call bean中相应的serter方法 //digester.addBeanPropertySetter("members/member/level","level"); return digester.parse(xmlFile); }
测试块代码:
public static void main(String[] args) { try { // 读入xml文件 String fPath = MembersParser.class.getClass().getResource("/org/oham/xml/test-members.xml").getPath(); File xmlFile = new File(fPath); //方式一 Members members = new MembersParser().parse(xmlFile); //方式二 //Members members = new MembersParser().parseInXMLRule(xmlFile); List<Member> mList = members.getMembers(); assert mList.size() == 2 : mList.size(); assert mList.get(0).getSkills().size() == 1 : mList.get(0).getSkills().size(); assert mList.get(0).getEquipments().size() == 2 : mList.get(0).getEquipments().size(); assert mList.get(0).getLevel() == 6 : mList.get(0).getLevel(); assert mList.get(1).getSkills().size() == 2 : mList.get(1).getSkills().size(); assert mList.get(1).getEquipments().size() == 0 : mList.get(1).getEquipments().size(); assert mList.get(1).getLevel() == 12 : mList.get(1).getLevel(); assert "Lulu".equals(mList.get(1).getName()) : mList.get(1).getName(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } }
// 使用方式二,将XPATH写到另一个xml封装起来,使用FromXmlRulesModule这个类读入xml并用其生成digester实例 // 使用一个内部类读入并解析rules xml private class RulesModule extends FromXmlRulesModule{ @Override protected void loadRules() { loadXMLRules(MembersParser.class.getClass().getResource("/org/oham/xml/test-members-rules.xml")); } } public Members parseInXMLRule(File xmlFile) throws IOException, SAXException { System.out.println("parse XPATH with XML rules"); // 使用RulesModule生成digester实例 Digester digester = DigesterLoader.newLoader(new RulesModule()).newDigester(); return digester.parse(xmlFile); }
封装XPATH规则的xml文件, test-members-rules.xml:
<?xml version="1.0"?> <!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> <pattern value="members"> <!-- 对应digester.addObjectCreate --> <object-create-rule classname="org.oham.xml.Members" /> <pattern value="member"> <object-create-rule classname="org.oham.xml.Member" /> <!-- 对应digester.addSetProperties --> <set-properties-rule /> <!-- 对应digester.addSetNext --> <set-next-rule methodname="addMember" paramtype="org.oham.xml.Member"/> <!-- 对应digester.addCallMethod --> <call-method-rule pattern="skill" methodname="addSkill" paramcount="0" /> <pattern value="equipment"> <call-method-rule methodname="addEquipment" paramcount="3" paramtypes="java.lang.String,java.lang.Integer,java.lang.String" /> <!-- 对应digester.addCallParam --> <call-param-rule paramnumber="0" /> <call-param-rule paramnumber="1" attrname="id" /> <call-param-rule paramnumber="2" attrname="version" /> </pattern> <pattern value="level"> <call-method-rule methodname="setLevel" paramcount="1" paramtypes="java.lang.Integer" /> <call-param-rule paramnumber="0" /> <!-- 对应digester.addBeanPropertySetter --> <!-- <bean-property-setter-rule propertyname="level" /> --> </pattern> </pattern> </pattern> </digester-rules>
使用schema验证
现在有以下规则用于test-members.xml,不符合规则者不得被解析,
1)members为根元素
2)member元素必须指定属性:name和species, member元素可以为空,多个
3)member元素中skill至少有一,equipment 可为空, level又且只有一,值的类型为正整数,最小为1,最大为99
4)equipment元素的id属性值唯一,注意在members元素范围内
据此定义schema如下test-members.xsd,关于schema,可参考w3c shcool 的教程
<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/test-members" xmlns="http://www.example.org/test-members" xmlns:tns="http://www.example.org/test-members" elementFormDefault="qualified" > <xs:complexType name="eqipment-type" > <xs:simpleContent> <xs:extension base="xs:string"> <xs:attribute name="id" use="required" type="xs:positiveInteger" /> <xs:attribute name="version" use="required" type="xs:string"/> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:complexType name="member-type"> <xs:sequence> <xs:element name="skill" type="xs:string" minOccurs="1" maxOccurs="unbounded" /> <xs:element name="equipment" type="eqipment-type" minOccurs="0" maxOccurs="unbounded" /> <xs:element name="level"> <xs:simpleType> <xs:restriction base="xs:positiveInteger"> <xs:minInclusive value="1"/> <xs:maxInclusive value="99"/> </xs:restriction> </xs:simpleType> </xs:element> </xs:sequence> <xs:attribute name="name" use="required" type="xs:string" /> <xs:attribute name="species" use="required" type="xs:string" /> </xs:complexType> <xs:element name="members"> <xs:complexType> <xs:sequence> <xs:element name="member" type="member-type" minOccurs="0" maxOccurs="unbounded"> </xs:element> </xs:sequence> </xs:complexType> <xs:unique name="idUnique"> <!-- 注意此处不加命名空间是无效的,这告了我N久 --> <xs:selector xpath="tns:member/tns:equipment"/> <xs:field xpath="@id" /> </xs:unique> </xs:element> </xs:schema>
修改test-members.xml如下:
<?xml version="1.0" encoding="UTF-8"?> <members xmlns="http://www.example.org/test-members" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.example.org/test-members test-members.xsd"> <member name="Oham" species="human"> <skill>create</skill> <equipment id="11" version="v1.0">Saurcer ship</equipment> <equipment id="12" version="v1.2-beta">Predator mask</equipment> <level>6</level> </member> <member name="Lulu" species="dog"> <skill>know the truth</skill> <skill>free the soul</skill> <!-- 按照规则,此处非法,因为前面已有id为12 的equipment --> <equipment id="12" version="v1.2-beta">Predator mask</equipment> <level>12</level> </member> </members>
修改MemberParser.java, 加入设置schema验证代码:
private void setSchemaValidate(Digester digester, File xmlFile) throws SAXException, IOException { SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); Schema schema = factory.newSchema(MembersParser.class.getClass().getResource("/org/oham/xml/test-members.xsd")); Validator validator = schema.newValidator(); validator.validate(new StreamSource(xmlFile)); }
调用parseInXMLRule测试,在其加入验证方法setSchemaValidate:
public Members parseInXMLRule(File xmlFile) throws IOException, SAXException { System.out.println("parse XPATH with XML rules"); // 使用RulesModule生成digester实例 Digester digester = DigesterLoader.newLoader(new RulesModule()).newDigester(); // 加入schema验证 setSchemaValidate(digester, xmlFile); return digester.parse(xmlFile); }
运行,结果抛了org.xml.sax.SAXParseException: cvc-identity-constraint.4.1:为元素“members”的标识约束“idUnique”声明了重复的唯一值 [12]。
注意一点,对于test-members.xml:
<?xml version="1.0" encoding="UTF-8"?> <members xmlns="http://www.example.org/test-members" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.example.org/test-members test-members.xsd"> ...
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 和 xsi:schemaLocation="http://www.example.org/test-members test-members.xsd" 只是在编辑xml的时候告知schema的位置,方便使用快捷方式编写,但跟程序运行时做schema验证无关,把这两句去掉,照样没问题,但必须指明命名空间,这里指明默认命名空间:xmlns="http://www.example.org/test-members"
相关推荐
标题“利用commons-digester解析XML”涉及到的是Java开发中的一种处理XML文档的工具——Apache Commons Digester。这个库提供了一种方便的方式来映射XML文档结构到Java对象,从而简化了XML数据的处理过程。 Apache ...
Digester 是 Apache Commons 中的一个工具类库,它用于解析 XML 文档,并根据预先定义的规则自动创建和配置 Java 对象。在上述问题中,我们看到一个 XML 文档表示了一个考试,其中包含了多个题目,每个题目有其编号...
本文将深入探讨如何使用Digester解析XML文件,以及在实际项目中如何应用。 首先,让我们了解什么是Apache Commons Digester。这是一个Java库,它的主要功能是读取XML文件,并基于一系列预先定义的规则(Rule),...
这个“digester解析xml必备包.rar”包含了三个关键的jar包,它们是实现Digester功能所必需的。 1. **commons-logging-1.2.jar**:这是Apache Commons Logging库的版本1.2。它提供了一个抽象层,允许开发者使用多种...
### 使用Digester解析XML文档示例 #### 一、Digester简介与应用场景 Digester是Apache Jakarta项目下的一个工具类库,它简化了基于SAX(Simple API for XML)的XML解析过程。Digester能够根据定义好的规则自动将...
这个“org.apache.commons.digester解析XML.rar”压缩包包含了一个测试工程,它演示了如何使用Digester库来解析XML文件并映射到Java对象上。下面将详细介绍这个库的功能、使用方法以及在实际开发中的应用。 1. **...
### Digester解析XML知识点详解 #### 一、Digester简介 **Digester** 是Apache Commons项目中的一个子项目,主要用于简化XML文档的解析工作。它建立在SAX的基础之上,通过定义一系列的模式(Pattern)和规则(Rule...
这个"digester解析XML文件实例"是一个很好的学习资源,帮助开发者理解如何在实际项目中运用Digester。 首先,我们要了解Digester的基本工作原理。Digester通过定义一系列规则(Rules),当解析到XML文档中特定的...
《digester解析XML详解》 在Java开发中,XML作为一种数据交换格式,广泛应用于配置文件、数据传输等场景。为了方便地将XML文档解析为Java对象,Apache组织提供了一个名为Digester的工具库,它允许开发者通过规则来...
**使用Digester解析XML并验证** 1. **设置 Digester 规则** 在使用Digester之前,我们需要定义一系列规则,告诉Digester在遇到XML文档的哪些元素时执行什么操作。这些规则通常涉及到创建新对象、设置对象属性或者...
在Java开发中,Struts框架提供了一个强大的工具——Digester,用于解析XML文件并自动创建、配置Java对象。本文将详细介绍如何使用Digester处理具有嵌套结构的XML文档,并通过一个具体的实例——"DigesterXmlTest"来...
**Digester** 是Apache Commons项目中的一个库,它专门用于解析XML文档,并基于规则将其转换为Java对象。Digester通过匹配XML元素结构来调用对象的方法或创建新对象,减少了手动解析XML的复杂性。这在配置驱动的Java...
在示例代码中, DigesterDriver演示了如何配置 Digester来解析XML文件,创建`Catalog`对象并填充其`Book`和`Magazine`子对象,以及相关的`Article`对象。每个元素的属性通过`addBeanPropertySetter()`设置,而对象...
不错的解析XML的类,主要利用org.apache.commons.digester.Digester;
本篇文章将详细介绍如何使用`Digester`解析XML,以及在使用过程中需要的依赖库。 首先,`Digester`的核心功能是通过定义规则来将XML元素与Java对象的属性或方法关联,这样在解析XML时,可以自动创建和填充Java对象...
Digester digester = DigesterLoader.createDigester(TestDigester.class.getClassLoader().getResource(Constants.CONFIG_MAPPINGRULE_PATH)); digester.setValidating(false);
《使用Digester解析XML的深度指南》 在Java开发中,处理XML文件是常见的任务,而Apache Commons Digester库提供了一种高效且便捷的方式来解析XML并将其映射到Java对象。本教程将深入探讨如何使用Digester来读取XML...