首先明白Digester是干什么的?它是apache开源项目Commons中的一个子项目,用于解析XML文档的工具。Digester底层采用的是SAX解析方式,通过遍历XML文档规则来进行处理。项目中有需要将XML文件中的信息解析为我们需要的内容时(如java类),使用Digester是非常方便的。话不多说,本案例使用的jdk版本是1.6。简单的jar包依赖如下:
重点:理解栈的概念
难点:当使用addObjectCreate()方法时,会创建一个对象进栈,许多重要的方法都是相对于栈顶元素或次栈顶元素来进行的。如:
<Orders>
<Order user="张三" date="2008-11-14" price="12279">
<goods id="1">
<name>IBM笔记本name>
<price>8999price>
<count>1count>
<total_price>8999total_price>
goods>
<goods id="2">
<name>雅戈尔西服name>
<price>1300price>
<count>2count>
<total_price>2600total_price>
goods>
Order>
Orders>
根据这个xml文件的各个节点得出,我们可以创建两个javabean来存储解析信息。分别为Order.java和good.java。
订单类
package cn.com.bean;
import java.util.ArrayList;
/**
* Order.java:订单类
* @author grk
*
*/
public class Order {
private String user; //对应标签中的user属性
private String date; //对应标签中的date属性
private String price; //对应标签中的price属性
private ArrayList goodsList = new ArrayList();//对应标签下的所有标签
//省略getter和setter...
// 添加商品到订单
public void add(Goods goods){
this.getGoodsList().add(goods);
}
// 重写toString()方法,方便于观察结果
@Override
public String toString() {
return "Order [user=" + user + ", date=" + date + ", price=" + price
+ ", goodsList=" + goodsList.toString() + "]";
}
}
商品类
package cn.com.bean;
package cn.com.bean;
/**
* Goods.java:商品类
* @author grk
*
*/
public class Goods {
private String id;
private String name;
private String price;
private String count;
private String total_price;
//省略getter和setter...
@Override
public String toString() {
return "Goods [id=" + id + ", name=" + name + ", price=" + price
+ ", count=" + count + ", total_price=" + total_price +"]";
}
}
解析类
package cn.com.test;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import org.apache.commons.digester.Digester;
import org.xml.sax.SAXException;
import cn.com.bean.Goods;
import cn.com.bean.Order;
/**
* title:通过digester的方式来解析Order.xml
* @author grk
* 重点:理解栈的概念
* 当使用addObjectCreate()方法时,创建一个对象进栈
* 以下的所有操作(有一种情况除外,表明调用的方法)都是对栈顶元素来讲的,除非调用addSetNext()方法,移除栈顶元素并执行次栈顶元素的指定方法
*
* addCallMethod(pattern, methodName):调用栈顶元素的指定方法
* addCallMethod(pattern, methodName, paramCount):调用栈顶元素的指定方法,可指定方法的参数个数
* addCallMethod(pattern, methodName, paramCount, paramTypes):调用栈顶元素的指定方法,可指定方法的参数个数,类型
*
* addCallParam(pattern, paramIndex):默认设置指定paramIndex参数为标签内容
* addCallParam(pattern, paramIndex, fromStack):设置指定paramIndex参数为栈顶元素
* addCallParam(pattern, paramIndex, stackIndex):设置指定paramIndex参数为?
* addCallParam(pattern, paramIndex, attributeName):设置指定paramIndex参数为标签属性attributeName的值
* addObjectParam(pattern, paramIndex, paramObj):设置指定paramIndex参数为paramObj
*
* addSetNext(pattern, methodName):调用次栈顶元素的methodName方法,一般为有一个参数的方法,将栈顶元素作为入参,如list的add方法
*
*/
public class ParseOrder {
public static void main(String[] args) {
parseByJavaBean();
}
/**
* 使用javaBean进行存储
*/
public static void parseByJavaBean(){
// 1.初始化Digester实例对象
Digester digester = new Digester();
// 2.解析标签节点
digester.addObjectCreate("Orders", ArrayList.class);//list进栈,栈顶元素的list对象
digester.addObjectCreate("Orders/Order", Order.class);//Order实例进栈,栈顶元素时Order实例对象
digester.addSetProperties("Orders/Order");//设置标签的属性
// 3.解析标签节点
digester.addObjectCreate("Orders/Order/goods", Goods.class);//Goods实例对象进栈
digester.addSetProperties("Orders/Order/goods");
digester.addBeanPropertySetter("Orders/Order/goods/name");//设置下的其他标签内容
digester.addBeanPropertySetter("Orders/Order/goods/price");
digester.addBeanPropertySetter("Orders/Order/goods/count");
digester.addBeanPropertySetter("Orders/Order/goods/total_price");
digester.addSetNext("Orders/Order/goods", "add");//Goods对象实例出栈
digester.addSetNext("Orders/Order", "add");//Order对象实例出栈
// 4.加载配置文件
String filePath = "";
filePath = System.getProperty("user.dir")+"/bin/config/Order.xml";
File file = new File(filePath);
// 5.解析
try {
ArrayList list = (ArrayList) digester.parse(file);
System.out.println(list.toString());
} catch (IOException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
}
}
}
运行结果
[Order [user=张三, date=2008-11-14, price=12279, goodsList=[Goods [id=1, name=IBM笔记本, price=8999, count=1, total_price=8999], Goods [id=2, name=雅戈尔西服, price=1300, count=2, total_price=2600]]]]
/**
* 使用list和map进行存储(过程复杂,不建议使用)
*/
public static void parseByMap(){
Digester digester = new Digester();
// 1.定义Orders节点规则,创建一个List集合
digester.addObjectCreate("Orders", ArrayList.class);
// 2.定义Orders/Order节点规则,创建一个Map集合用来存储属性和内容,并将此Map放在上一节点中的List
digester.addObjectCreate("Orders/Order", HashMap.class);
digester.addSetNext("Orders/Order", "add");
// 3.定义Orders/Order节点的属性
digester.addCallMethod("Orders/Order", "put", 2);//调用栈顶元素map的put方法
digester.addObjectParam("Orders/Order", 0, "name");//设置key
digester.addCallParam("Orders/Order", 1, "name");//设置value
digester.addCallMethod("Orders/Order", "put", 2);
digester.addObjectParam("Orders/Order", 0, "date");
digester.addCallParam("Orders/Order", 1, "date");
digester.addCallMethod("Orders/Order", "put", 2);
digester.addObjectParam("Orders/Order", 0, "price");
digester.addCallParam("Orders/Order", 1, "price");
// 4.定义一个List集合,用来存储Orders/Order节点下的标签
digester.addCallMethod("Orders/Order", "put", 2);
digester.addObjectCreate("Orders/Order", ArrayList.class);
digester.addObjectParam("Orders/Order", 0, "goodsList");
digester.addCallParam("Orders/Order", 1, true);
// 5.定义Orders/Order/goods节点规则,分别存储id,name,price,count,total_price属性或标签
digester.addObjectCreate("Orders/Order/goods", HashMap.class);
digester.addSetNext("Orders/Order/goods", "add");
digester.addCallMethod("Orders/Order/goods", "put", 2);
digester.addObjectParam("Orders/Order/goods", 0, "id");
digester.addCallParam("Orders/Order/goods", 1, "id");
digester.addCallMethod("Orders/Order/goods/name", "put", 2);
digester.addObjectParam("Orders/Order/goods/name", 0, "name");
digester.addCallParam("Orders/Order/goods/name", 1);
digester.addCallMethod("Orders/Order/goods/price", "put", 2);
digester.addObjectParam("Orders/Order/goods/price", 0, "price");
digester.addCallParam("Orders/Order/goods/price", 1);
digester.addCallMethod("Orders/Order/goods/count", "put", 2);
digester.addObjectParam("Orders/Order/goods/count", 0, "count");
digester.addCallParam("Orders/Order/goods/count", 1);
digester.addCallMethod("Orders/Order/goods/total_price", "put", 2);
digester.addObjectParam("Orders/Order/goods/total_price", 0, "total_price");
digester.addCallParam("Orders/Order/goods/total_price", 1);
String filePath = System.getProperty("user.dir")+"/bin/config/Order.xml";
System.out.println(filePath);
File file = new File(filePath);
System.out.println(file.getAbsolutePath());
try {
ArrayList list = (ArrayList) digester.parse(file);
System.out.println(list.toString());
} catch (IOException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
}
}
运行结果
[Order [user=张三, date=2008-11-14, price=12279, goodsList=[Goods [id=1, name=IBM笔记本, price=8999, count=1, total_price=8999], Goods [id=2, name=雅戈尔西服, price=1300, count=2, total_price=2600]]]]
OrderConfigRules.xml配置文件
<digester-rules>
<pattern value="Orders">
<object-create-rule classname="java.util.ArrayList" />
<pattern value="Order">
<object-create-rule classname="cn.com.bean.Order" />
<set-properties-rule/>
<pattern value="goods">
<object-create-rule classname="cn.com.bean.Goods" />
<set-properties-rule>
<alias attr-name="id" prop-name="id" />
set-properties-rule>
<bean-property-setter-rule pattern="name" propertyname="name" />
<bean-property-setter-rule pattern="price" propertyname="price" />
<bean-property-setter-rule pattern="count" propertyname="count" />
<bean-property-setter-rule pattern="total_price" propertyname="total_price" />
<set-next-rule methodname="add" paramtype="cn.com.bean.Goods"/>
pattern>
<set-next-rule methodname="add" paramtype="cn.com.bean.Order"/>
pattern>
pattern>
digester-rules>
java代码
public static void parseByXmlConfig() throws IOException, SAXException, URISyntaxException{
// 1.加载规则配置文件
URL rule = Thread.currentThread()
.getContextClassLoader()
.getResource("config/OrderConfigRules.xml");
// 2.加载待解析的配置文件Order.xml
Reader reader = null;
try {
reader = new InputStreamReader(
new FileInputStream(
new File(System.getProperty("user.dir") + "/bin/config/Order.xml")), "utf-8");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// 3.根据规则配置文件创建Digester实例对象
InputSource in = new InputSource(new InputStreamReader(new FileInputStream(new File(rule.toURI()))));
Digester digester = DigesterLoader.createDigester(in);
// 4.进行解析并打印结果
List list = (List) digester.parse(reader);
System.out.println(list.toString());
try {
if(reader != null){
reader.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
结果
[Order [user=张三, date=2008-11-14, price=12279, goodsList=[Goods [id=1, name=IBM笔记本, price=8999, count=1, total_price=8999], Goods [id=2, name=雅戈尔西服, price=1300, count=2, total_price=2600]]]]
java.lang.NoSuchMethodException: No such accessible method: add() on object: java.util.HashMap