jakarta的commons中的digester是非常优秀的xml解析工具,这个工具提供了从
xml->javabean的映射。相较于传统的w3c、sax方式解析xml文档,digester的层次更高,适合更懒得家伙。
下面这个例子简单,就是一个简单的存储数据,xml文件由schema文件约束,映射到对应的javabean当中,当然功能还不是很完善,作用也不够通用。
schema文件如下:
<?xml version="1.0" encoding="UTF-8"?> <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/final" xmlns:tns="http://www.example.org/final" elementFormDefault="qualified"> <element name="doc"> <complexType> <sequence> <element name="prvs" type="tns:prvs-type" /> <element name="usrs" type="tns:usrs-type" /> </sequence> </complexType> </element> <complexType name="prvs-type"> <sequence> <element name="prv" minOccurs="0" maxOccurs="unbounded" type="tns:prv-type" /> </sequence> </complexType> <complexType name="usrs-type"> <sequence> <element name="usr" minOccurs="0" maxOccurs="unbounded" type="tns:usr-type" /> </sequence> </complexType> <complexType name="prv-type"> <sequence> <element name="name" type="string" /> <element name="descr" type="string" /> </sequence> <attribute name="prv_id" type="integer" use="required" /> </complexType> <complexType name="usr-type"> <sequence> <element name="name" type="string" /> <element name="pwd" type="string" /> <element name="prvs"> <complexType> <sequence> <element name="prv_id" type="integer" minOccurs="0" maxOccurs="unbounded" /> </sequence> </complexType> </element> </sequence> <attribute name="usr_id" type="integer" use="required" /> </complexType> </schema>
对应2个具体的javabean:
一个是user类,代码如下:
package com.cxz.xmldb; import java.util.HashSet; import java.util.Set; import java.util.Collections; public class User { private int usr_id; private String name; private String pwd; private Set<Integer> prvs_id = Collections .synchronizedSet(new HashSet<Integer>()); private Set<Privilege> prvs = Collections .synchronizedSet(new HashSet<Privilege>()); public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getUsr_id() { return usr_id; } public void setUsr_id(int usr_id) { this.usr_id = usr_id; } public void addPrv(Privilege priv) throws DuplicateException { if (!prvs.add(priv)) throw new DuplicateException( "The privilege had been duplicated created."); } public void rmvPrv(Privilege priv) { prvs.remove(priv); } public void addPrvId(Integer priv) throws DuplicateException { if (!prvs_id.add(priv)) throw new DuplicateException( "The privilegeId had been duplicated created."); } public void rmvPrvId(Integer priv) { prvs_id.remove(priv); } public Set<Privilege> getPrvs() { return prvs; } public void setPrvs(Set<Privilege> prvs) { this.prvs = prvs; } public Set<Integer> getPrvs_id() { return prvs_id; } public void setPrvs_id(Set<Integer> prvs_id) { this.prvs_id = prvs_id; } @Override public int hashCode() { final int PRIME = 31; int result = 1; result = PRIME * result + usr_id; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; final User other = (User) obj; if (usr_id != other.usr_id) return false; return true; } }
另一个类是privilege类:
package com.cxz.xmldb; public class Privilege { private int prv_id; private String name; private String descr; public String getDescr() { return descr; } public void setDescr(String descr) { this.descr = descr; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getPrv_id() { return prv_id; } public void setPrv_id(int prv_id) { this.prv_id = prv_id; } @Override public int hashCode() { final int PRIME = 31; int result = 1; result = PRIME * result + prv_id; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; final Privilege other = (Privilege) obj; if (prv_id != other.prv_id) return false; return true; } }
下面这个是xml数据文件,包括了具体的关系:
<?xml version="1.0" encoding="UTF-8"?> <doc xmlns="http://www.example.org/final" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.example.org/final doc.xsd "> <prvs> <prv prv_id="0"> <name>read</name> <descr>read the file</descr> </prv> <prv prv_id="1"> <name>write</name> <descr>write the file</descr> </prv> <prv prv_id="2"> <name>execute</name> <descr>execute the file</descr> </prv> </prvs> <usrs> <usr usr_id="2003710201"> <name>cxz</name> <pwd>19841230</pwd> <prvs> <prv_id>0</prv_id> <prv_id>1</prv_id> <prv_id>2</prv_id> </prvs> </usr> <usr usr_id="2003710202"> <name>wm</name> <pwd>19841230</pwd> <prvs> <prv_id>0</prv_id> <prv_id>1</prv_id> </prvs> </usr> <usr usr_id="2003710203"> <name>wjt</name> <pwd>19841230</pwd> <prvs> <prv_id>1</prv_id> <prv_id>2</prv_id> </prvs> </usr> </usrs> <!-- <ulist> yxiong = role,role2... ben = role2 </ulist> <pri> role = a.jsp,b.action,.... </pri> --> </doc>
这个类代表了整个文档
package com.cxz.xmldb; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.Set; public class Document { private Set<Privilege> prvs = Collections .synchronizedSet(new HashSet<Privilege>()); private Set<User> usrs = Collections.synchronizedSet(new HashSet<User>()); public Document() { } public void addPrivilege(Privilege p) throws DuplicateException { if (!prvs.add(p)) throw new DuplicateException("Duplicated Priv"); } public void removePrivilege(Privilege p) { prvs.remove(p); } public void addUser(User u) throws DuplicateException { if (!usrs.add(u)) throw new DuplicateException("Duplicated Usr"); } public void removeUser(User u) { usrs.remove(u); } public void fetch() throws DuplicateException, Exception { for (User usr : usrs) { for(Integer prvId : usr.getPrvs_id()){ usr.addPrv(this.getOnePriv(prvId.intValue())); } } } private Privilege getOnePriv(int prvId) throws Exception{ for(Privilege priv: prvs){ if(priv.getPrv_id() == prvId) return priv; } throw new Exception("I didn't find the privilege entity."); } }
最后就是一个装配类,这个才是整个项目的重头:安装rule,从而建立映射关系。从而达到xml->javabean的映射。一个user对应多个privilege,类似于hibernate的映射:应该有一个容器,装载了所有的这个user实例所对应的privilege对象,当然,我采用的方法类似hibernate也是先装载一个id主,然后调用Document.fetch()进行填充,把id转化为具体的实例。
package com.cxz.xmldb; import java.io.IOException; import org.apache.commons.digester.CallMethodRule; import org.apache.commons.digester.CallParamRule; import org.apache.commons.digester.Digester; import org.apache.commons.digester.ObjectCreateRule; import org.apache.commons.digester.Rule; import org.apache.commons.digester.SetNextRule; import org.apache.commons.digester.SetPropertiesRule; import org.xml.sax.SAXException; public class SimpleDigester { /** * @param args * @throws Exception * @throws DuplicateException */ public static void main(String[] args) throws DuplicateException, Exception { Digester digester = new Digester(); Rule docCreate = new ObjectCreateRule("com.cxz.xmldb.Document"); digester.addRule("doc", docCreate); Rule prvCreate = new ObjectCreateRule("com.cxz.xmldb.Privilege"); digester.addRule("doc/prvs/prv", prvCreate); Rule usrCreate = new ObjectCreateRule("com.cxz.xmldb.User"); digester.addRule("doc/usrs/usr", usrCreate); Rule propertiesSet = new SetPropertiesRule(); digester.addRule("doc/prvs/prv", propertiesSet); digester.addRule("doc/usrs/usr", propertiesSet); digester.addRule("doc/prvs/prv", new SetNextRule("addPrivilege")); digester.addRule("doc/usrs/usr", new SetNextRule("addUser")); // digester.addRule("doc/prvs/prv", new CallMethodRule("setDescr", 1, // new Class[] { String.class })); // digester.addRule("doc/prvs/prv/descr", paramRule); // // digester.addRule("doc/prvs/prv", new CallMethodRule("setName", 1, // new Class[] { String.class })); // digester.addRule("doc/prvs/prv/name", paramRule); digester.addRule("doc/prvs/prv/name", new CallMethodRule("setName", 0, new Class[] { String.class })); digester.addRule("doc/prvs/prv/descr", new CallMethodRule("setDescr", 0, new Class[] { String.class })); digester.addRule("doc/usrs/usr/name", new CallMethodRule("setName", 0, new Class[] { String.class })); digester.addRule("doc/usrs/usr/pwd", new CallMethodRule("setPwd", 0, new Class[] { String.class })); digester.addRule("doc/usrs/usr/prvs/prv_id", new CallMethodRule( "addPrvId", 0, new Class[] { Integer.class })); Document doc = (Document) digester.parse(SimpleDigester.class .getClassLoader().getResource("doc.xml")); doc.fetch(); } }