使用Digester解析XML文件的三种方式小结

 更新时间:2024年01月26日 08:40:26   作者:代码哲学  
Digester是apache开源项目Commons中的一个子项目,用于解析XML文档的工具,本文为大家整理了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文件的资料请关注脚本之家其它相关文章!

相关文章

  • Springboot+MDC+traceId日志中打印唯一traceId

    Springboot+MDC+traceId日志中打印唯一traceId

    本文主要介绍了Springboot+MDC+traceId日志中打印唯一traceId,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-10-10
  • Spring AOP核心功能示例代码详解

    Spring AOP核心功能示例代码详解

    AOP面向切面编程,它是一种思想,它是对某一类事情的集中处理,而AOP是一种思想,而Spring AOP是一个框架,提供了一种对AOP思想的实现,它们的关系和loC与DI类似,这篇文章主要介绍了Spring AOP统一功能处理示例代码,需要的朋友可以参考下
    2023-02-02
  • SpringMVC使用RESTful接口案例

    SpringMVC使用RESTful接口案例

    RESTful是一种web软件风格,它不是标准也不是协议,它不一定要采用,只是一种风格,它倡导的是一个资源定位(url)及资源操作的风格,这篇文章主要介绍了SpringBoot使用RESTful接口
    2022-12-12
  • Springboot2.0配置JPA多数据源连接两个mysql数据库方式

    Springboot2.0配置JPA多数据源连接两个mysql数据库方式

    这篇文章主要介绍了Springboot2.0配置JPA多数据源连接两个mysql数据库方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • SpringBoot整合MyBatis-Plus的示例代码

    SpringBoot整合MyBatis-Plus的示例代码

    这篇文章主要介绍了SpringBoot整合MyBatis-Plus的示例代码,使用 MyBatis-Plus 可以减少大量的开发时间,单表的增删改查可以不用写 sql 语句,本文主要介绍整合需要主要事项,需要的朋友可以参考下
    2022-03-03
  • IntelliJ Idea 2020.1 正式发布,官方支持中文(必看)

    IntelliJ Idea 2020.1 正式发布,官方支持中文(必看)

    这篇文章主要介绍了IntelliJ Idea 2020.1 正式发布,官方支持中文了,本文通过截图的形式给大家展示,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-04-04
  • Java实现按行读取大文件

    Java实现按行读取大文件

    这篇文章主要介绍了Java实现按行读取大文件的方法的小结,非常的简单实用,有需要的小伙伴尅参考下。
    2015-05-05
  • Spring Data Jpa+SpringMVC+Jquery.pagination.js实现分页示例

    Spring Data Jpa+SpringMVC+Jquery.pagination.js实现分页示例

    本文介绍了Spring Data Jpa+SpringMVC+Jquery.pagination.js实现分页示例,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-12-12
  • Java设计模式中的装饰器模式简析

    Java设计模式中的装饰器模式简析

    这篇文章主要介绍了Java设计模式中的装饰器模式简析,装饰模式能够实现动态的为对象添加功能,是从一个对象外部来给对象添加功能,通常给对象添加功能,要么直接修改对象添加相应的功能,要么派生对应的子类来扩展,抑或是使用对象组合的方式,需要的朋友可以参考下
    2023-12-12
  • Java中临时文件目录的使用

    Java中临时文件目录的使用

    :Java提供了系统属性java.io.tmpdir来获取默认临时文件目录,适用于不同操作系统,使用Files.createTempFile方法创建临时文件,并在不需要时应及时删除,下面就来介绍一下
    2024-10-10

最新评论