您的位置:首页 > 其它

Digester解析xml文件

2016-03-10 16:05 417 查看
刚刚学了一下Digester如何解析xml文件,所以记录下来,方便以后查看。
 
    一般用来读取xml文件的工具包有DOM、SAX和JDOM等,但用过的人都知道,它们属于比较底层的API,写起来代码量很大,而且如果修改了xml文件的格式,代码也要做大幅度的改动。而使用Apache Jakarta的Digester,解析XML文件非常方便且不需要过多的关心底层的具体解析过程。Digester本来仅仅是Jakarta Struts中的一个工具,用于处理struts-config.xml配置文件。显然,将XML文件转换成相应的Java对象是一项很通用的功能,这个工具理应具有更广泛的用途,所以很快它就在Jakarta Commons项目(用于提供可重用的Java组件库)中有了一席之地。Digester由"事件"驱动,通过调用预定义的规则操作对象栈,将XML文件转换为Java对象。
    工作原理如下: Digester底层采用SAX(Simple API for XML)析XML文件,所以很自然的,对象转换由"事件"驱动,在遍历每个节点时,检查是否有匹配模式,如果有,则执行规则定义的操作,比如创建特定的Java对象,或调用特定对象的方法等。此处的XML元素根据匹配模式(matching pattern)识别,而相关操作由规则(rule)定义。
    如下xml代码,右边是左边元素对应的匹配模式:
 

[xhtml] view plaincopy

<datasources>          'datasources'   

  <datasource>         'datasources/datasource'   

    <name/>            'datasources/datasource/name'   

    <driver/>          'datasources/datasource/driver'    

  </datasource>   

  <datasource>         'datasources/datasource'   

    <name/>            'datasources/datasource/name'   

    <driver/>          'datasources/datasource/driver'    

  </datasource>   

</datasources>   

 

 
例子1:
下面介绍解析xml文件的代码
 
下面是存放地址及编码的xml文件viewcache.xml(片段):
 

[xhtml] view plaincopy

<?xml version="1.0" encoding="UTF-8" ?>  

<viewcache>  

    <areas>  

        <area>  

            <id>1098</id>  

            <parentId>1001</parentId>  

            <areaType>province</areaType>  

            <name>北京</name>  

            <ordering>1867</ordering>  

        </area>  

        <area>  

            <id>1099</id>  

            <parentId>1098</parentId>  

            <areaType>capital</areaType>  

            <name>北京</name>  

            <ordering>1868</ordering>  

            <phoneArea>010</phoneArea>  

        </area>  

        <area>  

            <id>4476</id>  

            <parentId>1099</parentId>  

            <areaType>county</areaType>   

            <name>北京市朝阳区</name>  

            <ordering>1869</ordering>  

            <phoneArea>010</phoneArea>  

        </area>  

        <area>  

            <id>4477</id>  

            <parentId>1099</parentId>  

            <areaType>county</areaType>  

            <name>北京市崇文区</name>  

            <ordering>1870</ordering>  

            <phoneArea>010</phoneArea>  

        </area>  

        <area>  

            <id>4478</id>  

            <parentId>1099</parentId>  

            <areaType>county</areaType>  

            <name>北京市大兴区</name>  

            <ordering>1871</ordering>  

            <phoneArea>010</phoneArea>  

        </area>  

    </areas>  

</viewcache>  

 

此xml文件分3层结构,分别为:
<viewcache>节点 其下包含1个<areas>节点
<areas>节点 其下包含多个<area>节点
<area>节点,其下包含各种信息节点 : 如:<id> 、<name>等。 
我们的操作目标是把area中的信息节点的内容提取出来。 
把每个<arrea>看做为一个对象,<area>中信息节点的内容为对象中的元素。 
设定一个类Area.java 其内容如下: 
 

[java] view plaincopy

public class Area {  

    private int    id;  

    private String name;  

    private String areaType;  

    private int    parentId;  

    private int    ordering;  

    private String zip;  

      

    private String phoneArea;  

      

    public int getOrdering() {  

        return ordering;  

    }  

    public void setOrdering(int ordering) {  

        this.ordering = ordering;  

    }  

    public String getAreaType() {  

        return areaType;  

    }  

    public void setAreaType(String areaType) {  

        this.areaType = areaType;  

    }  

    public int getId() {  

        return id;  

    }  

    public void setId(int id) {  

        this.id = id;  

    }  

    public String getName() {  

        return name;  

    }  

    public void setName(String name) {  

        this.name = name;  

    }  

    public int getParentId() {  

        return parentId;  

    }  

    public void setParentId(int parentId) {  

        this.parentId = parentId;  

    }  

      

    public String getZip() {  

        return zip;  

    }  

      

    public void setZip(String zip) {  

        this.zip = zip;  

    }  

      

    public String getPhoneArea() {  

        return phoneArea;  

    }  

      

    public void setPhoneArea(String phoneArea) {  

        this.phoneArea = phoneArea;  

    }  

}  

 

 

创建一个ViewCache类,用来保存解析后的所有对象:
 

[java] view plaincopy

public class ViewCache {  

    private List areaList             = new ArrayList();  

    public List getAreaList() {  

        return areaList;  

    }  

    public void setAreaList(List areaList) {  

        this.areaList = areaList;  

    }  

      

    // 供Digester调用的方法  

    public void addArea(Area area) {  

        this.areaList.add(area);  

    }  

}  

 

 

创建一个类AreaDigester,对xml文件进行解析:
 

[java] view plaincopy

public class AreaDigester {  

      

    public ViewCache digester() throws Exception {  

        Digester digester = new Digester();  

        digester.setValidating(false);  

        digester.addObjectCreate("viewcache/areas", ViewCache.class);  

        // 指明匹配模式和要创建的类   

        digester.addObjectCreate("viewcache/areas/area", Area.class);  

        // 设置对象属性,与xml文件对应,不设置则是默认  

        digester.addBeanPropertySetter("viewcache/areas/area/id", "id");  

        digester.addBeanPropertySetter("viewcache/areas/area/parentId", "parentId");  

        digester.addBeanPropertySetter("viewcache/areas/area/name", "name");  

        digester.addBeanPropertySetter("viewcache/areas/area/areaType", "areaType");  

        digester.addBeanPropertySetter("viewcache/areas/area/ordering", "ordering");  

        digester.addBeanPropertySetter("viewcache/areas/area/zip", "zip");  

        digester.addBeanPropertySetter("viewcache/areas/area/phoneArea", "phoneArea");  

        // 当移动到下一个标签中时的动作  

        digester.addSetNext("viewcache/areas/area", "addArea");  

          

        ViewCache vc = null;  

        try {  

            vc = (ViewCache) digester.parse("viewcache.xml");  

        } catch (IOException e) {  

            throw new Exception(e);  

        } catch (SAXException e) {  

            throw new Exception(e);  

        }  

        return vc;  

    }  

}  

 

调用AreaDigester的digester方法,即可把解析后的所有地址对象,存放在ViewCache的list中。
 
例子2:
要解析的xml文件books.xml如下:
 

[xhtml] view plaincopy

<?xml version="1.0" encoding="UTF-8" ?>   

<library name="alibaba图书馆">   

     <book title ="thinking in java"  author="xxx">   

         <chapter>   

             <no>第一章</no>   

             <caption>第一章的标题</caption>   

         </chapter>   

         <chapter>   

             <no>第二章</no>   

             <caption>第二章的标题</caption>   

         </chapter>   

     </book>   

     <book title="effective java"  author="yyy">   

         <chapter>   

             <no>第一章</no>   

             <caption>第一章的标题</caption>   

         </chapter>   

     </book>   

</library>  

 

Library类如下:
 

[java] view plaincopy

public class Library {  

    private String name;  

    private List<Book> bookList = new ArrayList<Book>();  

      

    public String getName() {  

        return name;  

    }  

      

    public void setName(String name) {  

        this.name = name;  

    }  

      

    public List<Book> getBookList() {  

        return bookList;  

    }  

      

    public void addBook(Book book) {  

        bookList.add(book);  

    }  

}  

 

Book类如下:
 

[java] view plaincopy

public class Book {  

  

    private String        title;  

    private String        author;  

    private List<Chapter> chapters = new ArrayList<Chapter>();  

  

    /** 

     * 这个方法,用来演示xml的解析时用的另一种方式 

     * @param title 

     * @param author 

     */  

    public void setBookInfo(String title, String author) {  

        this.title = title;  

        this.author = author;  

    }  

  

    public void addChapter(Chapter chapter) {  

        this.chapters.add(chapter);  

    }  

      

    public String getTitle() {  

        return title;  

    }  

      

    public void setTitle(String title) {  

        this.title = title;  

    }  

      

    public String getAuthor() {  

        return author;  

    }  

      

    public void setAuthor(String author) {  

        this.author = author;  

    }  

      

    public List<Chapter> getChapters() {  

        return chapters;  

    }  

  

    public void setChapters(List<Chapter> chapters) {  

        this.chapters = chapters;  

    }  

}  

 

Chapter类如下:
 

[java] view plaincopy

public class Chapter {  

  

    private String no;  

    private String caption;  

  

    public String getNo() {  

        return no;  

    }  

  

    public void setNo(String no) {  

        this.no = no;  

    }  

  

    public String getCaption() {  

        return caption;  

    }  

  

    public void setCaption(String caption) {  

        this.caption = caption;  

    }  

}  

 

解析xml的类如下:
 

[java] view plaincopy

public class MainTest {  

  

    /** 

     * @param args 

     */  

    public static void main(String[] args) {  

        // 建立一个Digester对象  

        Digester digester = new Digester();  

        //指定它不要用DTD验证XML文档的合法性——这是因为我们没有为XML文档定义DTD  

        digester.setValidating(false);  

        // 从library标签开始解析,并新建一个Library对象做为根对象  

        digester.addObjectCreate("library", Library.class);  

        // 根据library标签属性值设置对象的属性,一次可以设置多个属性  

        digester.addSetProperties("library");  

        // 也可以用下面的方法,指定propertyName  

        // digester.addSetProperties("library", "name", "name");  

  

        // -----第1层元素开始  

        digester.addObjectCreate("library/book", Book.class);  

        //digester.addSetProperties("library/book");  

        // 可以用以下三条语句代替  

        digester.addCallMethod("library/book", "setBookInfo", 2);  

        digester.addCallParam("library/book", 0, "title");  

        digester.addCallParam("library/book", 1, "author");  

        /** 

         * addCallParam(String rule, int  paraIndex,String attributeName) 

         * 该方法与addCallMethod配合使用 

         * int paraIndex:表明需要填充的方法形参序号,从 0 开始,方法由addCallMethod指定 

         * String attributeName:指定标签属性名称 

         */  

          

          

        // -----第2层元素开始  

        digester.addObjectCreate("library/book/chapter", Chapter.class);  

        /** addBeanPropertySetter()是将子节点转换为对象的属性,这个方法还可以有第二个参数,当对象的属性名和子节点的名字不一样时用来指定对象的属性名 

            该方法的作用及使用方法类似于addSetProperties,只不过它是用String rule规则所指定标签的值(而不是标签的属性)来调用对象的setter*/  

        digester.addBeanPropertySetter("library/book/chapter/no");  

        // digester.addBeanPropertySetter("library/book/chapter/no", "no");  

          

        /** addCallMethod(String rule,String methodName, int  paraNumber) 方法 

         * 同样是设置对象的属性,但是方式更加灵活,不需要对象具有setter 

         * 当paraNumber = 0时,可以单独使用(表明为标签的值来调用),不然需要配合addCallParam方法 

        */  

        // digester.addBeanPropertySetter("library/book/chapter/caption");  

        // 下面的方法,可以用来代替上一句,作用是一样的   

        digester.addCallMethod("library/book/chapter/caption", "setCaption", 0);  

  

        // addSetNext()是说在再次遇到匹配节点后, 调用当前对象(Chapter类的对象)的父对象(Book类的对象)的方法,方法参数是当前层元素的对象  

        digester.addSetNext("library/book/chapter", "addChapter");  

        // -----第2层元素结束  

  

        digester.addSetNext("library/book", "addBook");  

        // -----第1层元素结束  

  

        try {  

            // 解析XML文件,并得到ROOT元素  

            Library library = (Library) digester.parse(MainTest.class.getResourceAsStream("books.xml"));  

            System.out.println(" 图书馆: " + library.getName());  

            System.out.println(" 共藏书: " + library.getBookList().size() + " 本 ");  

            System.out.println(" ***************************** ");  

  

            for (Book book : library.getBookList()) {  

                System.out.println(" 书名: " + book.getTitle() + "        作者: " + book.getAuthor());  

                System.out.println(" ------------------------------ ");  

                // 显示章节  

                System.out.println(" 共 " + book.getChapters().size() + " 章 ");  

                for (Chapter chapter : book.getChapters()) {  

                    System.out.println(chapter.getNo() + ": " + chapter.getCaption());  

                }  

                System.out.println(" ------------------------------ ");  

            }  

        } catch (IOException e) {  

            e.printStackTrace();  

        } catch (SAXException e) {  

            e.printStackTrace();  

        }  

    }  

}  

 

 
 
例子3:
 
Digester解析xml的规则,除了在java类中描述设置之外,还可以把解析规则放在xml文件中。以例子2中的代码为例,规则在books-rule.xml文件中,内容如下:(The DTD is distributed in the 
commons-digester.jar
. It can be found at 
org/apache/commons/digester/xmlrules/digester-rules.dtd,通过查看DTD文件,可以知道有哪些标签可以使用
)
 

[xhtml] view plaincopy

<?xml version="1.0" encoding="UTF-8" ?>  

<!DOCTYPE digester-rules PUBLIC  

   "-//Jakarta Apache //DTD digester-rules XML V1.0//EN"  

   "digester-rules.dtd">   

<digester-rules>    

    <object-create-rule pattern="library" classname="com.alibaba.chj.digester.Library" />    

    <set-properties-rule pattern="library">    

        <alias attr-name="name" prop-name="name" />    

    </set-properties-rule>    

    <pattern value="library/book">    

        <object-create-rule classname="com.alibaba.chj.digester.Book" />    

        <set-properties-rule />    

        <pattern value="chapter">    

            <object-create-rule classname="com.alibaba.chj.digester.Chapter" />    

            <bean-property-setter-rule pattern="no" propertyname="no" />  

            <bean-property-setter-rule pattern="caption" propertyname="caption" />  

            <set-next-rule methodname="addChapter" />    

        </pattern>       

        <set-next-rule methodname="addBook" />    

    </pattern>    

</digester-rules>    

 

 
解析xml类的代码,修改为:
 

[java] view plaincopy

public class MainTest {  

  

    /** 

     * @param args 

     */  

    public static void main(String[] args) {  

        try {      

            Digester digester = DigesterLoader.createDigester(DigesterXmlRuleTest.class.getResource("books-rule.xml"));      

            Library library = (Library) digester.parse(DigesterXmlRuleTest.class.getResourceAsStream("books.xml"));      

            System.out.println(" 图书馆: " + library.getName());  

            System.out.println(" 共藏书: " + library.getBookList().size() + " 本 ");  

            System.out.println(" ***************************** ");  

  

            for (Book book : library.getBookList()) {  

                System.out.println(" 书名: " + book.getTitle() + "        作者: " + book.getAuthor());  

                System.out.println(" ------------------------------ ");  

                // 显示章节  

                System.out.println(" 共 " + book.getChapters().size() + " 章 ");  

                for (Chapter chapter : book.getChapters()) {  

                    System.out.println(chapter.getNo() + ": " + chapter.getCaption());  

                }  

                System.out.println(" ------------------------------ ");  

            }     

        } catch (IOException e) {  

            e.printStackTrace();  

        } catch (SAXException e) {  

            e.printStackTrace();  

        }   

    }  

}  

 

用于规则放在xml文件中,所以解析的类,显得更加简洁一些。
 
 
Digester FAQ: http://wiki.apache.org/commons/Digester/FAQ

版权声明:本文为博主原创文章,未经博主允许不得转载。
/article/8032372.html
v
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: