使用Digester解析XML文件的三种方式小结
作者:代码哲学
1. Digester解析XML文件的三种方式
作用及依赖jar包
首先明白Digester是干什么的?它是apache开源项目Commons中的一个子项目,用于解析XML文档的工具。Digester底层采用的是SAX解析方式,通过遍历XML文档规则来进行处理。项目中有需要将XML文件中的信息解析为我们需要的内容时(如java类),使用Digester是非常方便的。话不多说,本案例使用的jdk版本是1.6。简单的jar包依赖如下:
- commons-digester-1.8.jar
- commons-logging.jar
- commons-collections-3.2.1.jar
- commons-beanutils-1.7.0.jar
2. 重点和难点
重点:理解栈的概念
难点:当使用addObjectCreate()方法时,会创建一个对象进栈,许多重要的方法都是相对于栈顶元素或次栈顶元素来进行的。
如:
addCallMethod(pattern, methodName):调用栈顶元素的指定方法
addCallMethod(pattern, methodName, paramCount):调用栈顶元素的指定方法,可指定方法的参数个数
addCallMethod(pattern, methodName, paramCount, paramTypes):调用栈顶元素的指定方法,可指定方法的参数个数,类型
3. XML文件
<?xml version="1.0" encoding="UTF-8" ?> <Orders> <Order user="张三" date="2008-11-14" price="12279"> <goods id="1"> <name>IBM笔记本</name> <price>8999</price> <count>1</count> <total_price>8999</total_price> </goods> <goods id="2"> <name>雅戈尔西服</name> <price>1300</price> <count>2</count> <total_price>2600</total_price> </goods> </Order> </Orders>
4. 通过不同的方式解析这个xml文件
4.1 通过java编码方式解析(javabean存储)
根据这个xml文件的各个节点得出,我们可以创建两个javabean来存储解析信息。分别为Order.java和good.java。
// 订单类 package cn.com.bean; import java.util.ArrayList; /** * Order.java:订单类 * @author ypykip * */ public class Order { private String user; //对应<Order>标签中的user属性 private String date; //对应<Order>标签中的date属性 private String price; //对应<Order>标签中的price属性 //对应<Order>标签下的所有<good>标签 private ArrayList<Goods> goodsList = new ArrayList<Goods>(); //省略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 ypykip * */ 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 +"]"; } } // 解析类 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.解析<Order>标签节点 //list进栈,栈顶元素的list对象 digester.addObjectCreate("Orders", ArrayList.class); //Order实例进栈,栈顶元素时Order实例对象 digester.addObjectCreate("Orders/Order", Order.class); //设置<Order>标签的属性 digester.addSetProperties("Orders/Order"); // 3.解析<goods>标签节点 //Goods实例对象进栈 digester.addObjectCreate("Orders/Order/goods", Goods.class); digester.addSetProperties("Orders/Order/goods"); //设置<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"); //Goods对象实例出栈 digester.addSetNext("Orders/Order/goods", "add"); //Order对象实例出栈 digester.addSetNext("Orders/Order", "add"); // 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]]]]
4.2 通过java编码方式解析(list和map存储)
/** * 使用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(); } }
4.3 通过xml配置方式解析
4.3.1 OrderConfigRule.xml 配置文件
<?xml version="1.0" encoding="UTF-8"?> <digester-rules> <pattern value="Orders"> <object-create-rule classname="java.util.ArrayList" /> <!-- 配置<Order>标签 --> <pattern value="Order"> <object-create-rule classname="cn.com.bean.Order" /> <set-properties-rule/> <!-- 配置<goods>标签 --> <pattern value="goods"> <object-create-rule classname="cn.com.bean.Goods" /> <set-properties-rule> <alias attr-name="id" prop-name="id" /><!-- id属性对应javabean的id --> </set-properties-rule> <bean-property-setter-rule pattern="name" propertyname="name" /><!-- name属性对应javabean的name --> <bean-property-setter-rule pattern="price" propertyname="price" /><!-- price标签对应javabean的price --> <bean-property-setter-rule pattern="count" propertyname="count" /><!-- count标签对应javabean的count --> <bean-property-setter-rule pattern="total_price" propertyname="total_price" /><!-- total_price标签对应javabean的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>
4.3.2 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]]]]
5.总结
如果需要调用addSetNext()方法时,addObjectCreate()方法和addSetNext()方法最好成对出现
首先要知道addSetNext()方法是调用次栈顶元素的方法,一般以栈顶元素为参数。如上例中使用list和map的方式进行存储时,创建顺序分别是Orders—>Order—>goods,对应的list和map分别是list(Orders)—>map(Order)—>list(goodsList)—>map(goods)。当遇到Orders/Order节点时,分别创建了一个map和一个list,分别表示订单和商品集合。当遇到 < /order> 结束标签时需要调用list(Orders)的add()方法,即需要此时的栈顶元素是map(Order)和次栈顶元素是list(Orders)。如果addSetNext()写在了list(goodsList)创建之后,此时的栈顶元素和次栈顶元素分别是list(goodsList),map(Order),而map是没有add方法的,所以会报错:
java.lang.NoSuchMethodException: No such accessible method: add() on object: java.util.HashMap
通过使用java编码和配置规则两种方式都可以实现解析,其实两者看上去十分相似熟练了其中一种,另一种也就无师自通
以上就是使用Digester解析XML文件的三种方式小结的详细内容,更多关于Digester解析XML文件的资料请关注脚本之家其它相关文章!