Digester解析xml详解

原文地址:http://blog.csdn.net/caihaijiang/article/details/5944955

    一般用来读取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","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文件中,所以解析的类,显得更加简洁一些。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


php输出xml格式字符串
J2ME Mobile 3D入门教程系列文章之一
XML轻松学习手册
XML入门的常见问题(一)
XML入门的常见问题(三)
XML轻松学习手册(2)XML概念
xml文件介绍及使用
xml编程(一)-xml语法
XML文件结构和基本语法
第2章 包装类
XML入门的常见问题(二)
Java对象的强、软、弱和虚引用
JS解析XML文件和XML字符串详解
java中枚举的详细使用介绍
了解Xml格式
XML入门的常见问题(四)
深入SQLite多线程的使用总结详解
PlayFramework完整实现一个APP(一)
XML和YAML的使用方法
XML轻松学习总节篇