Digester解析xml详解

来源:互联网 发布:spark 网页端口 编辑:程序博客网 时间:2024/05/16 15:32
原文地址: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", 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文件中,所以解析的类,显得更加简洁一些。

0 0
原创粉丝点击