刚刚学了一下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代码,右边是左边元素对应的匹配模式:
- <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(片段):
- <?xmlversion="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 其内容如下:
- publicclassArea{
- privateintid;
- privateStringname;
- privateStringareaType;
- privateintparentId;
- privateintordering;
- privateStringzip;
- privateStringphoneArea;
- publicintgetOrdering(){
- returnordering;
- }
- publicvoidsetOrdering(intordering){
- this.ordering=ordering;
- }
- publicStringgetAreaType(){
- returnareaType;
- }
- publicvoidsetAreaType(StringareaType){
- this.areaType=areaType;
- }
- publicintgetId(){
- returnid;
- }
- publicvoidsetId(intid){
- this.id=id;
- }
- publicStringgetName(){
- returnname;
- }
- publicvoidsetName(Stringname){
- this.name=name;
- }
- publicintgetParentId(){
- returnparentId;
- }
- publicvoidsetParentId(intparentId){
- this.parentId=parentId;
- }
- publicStringgetZip(){
- returnzip;
- }
- publicvoidsetZip(Stringzip){
- this.zip=zip;
- }
- publicStringgetPhoneArea(){
- returnphoneArea;
- }
- publicvoidsetPhoneArea(StringphoneArea){
- this.phoneArea=phoneArea;
- }
- }
创建一个ViewCache类,用来保存解析后的所有对象:
- publicclassViewCache{
- privateListareaList=newArrayList();
- publicListgetAreaList(){
- returnareaList;
- }
- publicvoidsetAreaList(ListareaList){
- this.areaList=areaList;
- }
- publicvoidaddArea(Areaarea){
- this.areaList.add(area);
- }
- }
创建一个类AreaDigester,对xml文件进行解析:
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 {
File file = new File("viewcache.xml");
BufferedReader read = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
StringBuffer sb = new StringBuffer();
String content = "";
while((content=read.readLine()) != null){
sb.append(content);
}
vc = (ViewCache) digester.parse(new StringReader(sb.toString()));
} catch (IOException e) {
throw new Exception(e);
} catch (SAXException e) {
throw new Exception(e);
}
return vc;
}
}
调用AreaDigester的digester方法,即可把解析后的所有地址对象,存放在ViewCache的list中。
例子2:
要解析的xml文件books.xml如下:
- <?xmlversion="1.0"encoding="UTF-8"?>
- <libraryname="alibaba图书馆">
- <booktitle="thinkinginjava"author="xxx">
- <chapter>
- <no>第一章</no>
- <caption>第一章的标题</caption>
- </chapter>
- <chapter>
- <no>第二章</no>
- <caption>第二章的标题</caption>
- </chapter>
- </book>
- <booktitle="effectivejava"author="yyy">
- <chapter>
- <no>第一章</no>
- <caption>第一章的标题</caption>
- </chapter>
- </book>
- </library>
Library类如下:
- publicclassLibrary{
- privateStringname;
- privateList<Book>bookList=newArrayList<Book>();
- publicStringgetName(){
- returnname;
- }
- publicvoidsetName(Stringname){
- this.name=name;
- }
- publicList<Book>getBookList(){
- returnbookList;
- }
- publicvoidaddBook(Bookbook){
- bookList.add(book);
- }
- }
Book类如下:
- publicclassBook{
- privateStringtitle;
- privateStringauthor;
- privateList<Chapter>chapters=newArrayList<Chapter>();
- publicvoidsetBookInfo(Stringtitle,Stringauthor){
- this.title=title;
- this.author=author;
- }
- publicvoidaddChapter(Chapterchapter){
- this.chapters.add(chapter);
- }
- publicStringgetTitle(){
- returntitle;
- }
- publicvoidsetTitle(Stringtitle){
- this.title=title;
- }
- publicStringgetAuthor(){
- returnauthor;
- }
- publicvoidsetAuthor(Stringauthor){
- this.author=author;
- }
- publicList<Chapter>getChapters(){
- returnchapters;
- }
- publicvoidsetChapters(List<Chapter>chapters){
- this.chapters=chapters;
- }
- }
Chapter类如下:
- publicclassChapter{
- privateStringno;
- privateStringcaption;
- publicStringgetNo(){
- returnno;
- }
- publicvoidsetNo(Stringno){
- this.no=no;
- }
- publicStringgetCaption(){
- returncaption;
- }
- publicvoidsetCaption(Stringcaption){
- this.caption=caption;
- }
- }
解析xml的类如下:
- publicclassMainTest{
- publicstaticvoidmain(String[]args){
- Digesterdigester=newDigester();
- digester.setValidating(false);
- digester.addObjectCreate("library",Library.class);
- digester.addSetProperties("library");
- digester.addObjectCreate("library/book",Book.class);
- digester.addCallMethod("library/book","setBookInfo",2);
- digester.addCallParam("library/book",0,"title");
- digester.addCallParam("library/book",1,"author");
- digester.addObjectCreate("library/book/chapter",Chapter.class);
- digester.addBeanPropertySetter("library/book/chapter/no");
- digester.addCallMethod("library/book/chapter/caption","setCaption",0);
- digester.addSetNext("library/book/chapter","addChapter");
- digester.addSetNext("library/book","addBook");
- try{
- Librarylibrary=(Library)digester.parse(MainTest.class.getResourceAsStream("books.xml"));
- System.out.println("图书馆:"+library.getName());
- System.out.println("共藏书:"+library.getBookList().size()+"本");
- System.out.println("*****************************");
- for(Bookbook:library.getBookList()){
- System.out.println("书名:"+book.getTitle()+"作者:"+book.getAuthor());
- System.out.println("------------------------------");
- System.out.println("共"+book.getChapters().size()+"章");
- for(Chapterchapter:book.getChapters()){
- System.out.println(chapter.getNo()+":"+chapter.getCaption());
- }
- System.out.println("------------------------------");
- }
- }catch(IOExceptione){
- e.printStackTrace();
- }catch(SAXExceptione){
- 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文件,可以知道有哪些标签可以使用 )
- <?xmlversion="1.0"encoding="UTF-8"?>
- <!DOCTYPEdigester-rulesPUBLIC
- "-//JakartaApache//DTDdigester-rulesXMLV1.0//EN"
- "digester-rules.dtd">
- <digester-rules>
- <object-create-rulepattern="library"classname="com.alibaba.chj.digester.Library"/>
- <set-properties-rulepattern="library">
- <aliasattr-name="name"prop-name="name"/>
- </set-properties-rule>
- <patternvalue="library/book">
- <object-create-ruleclassname="com.alibaba.chj.digester.Book"/>
- <set-properties-rule/>
- <patternvalue="chapter">
- <object-create-ruleclassname="com.alibaba.chj.digester.Chapter"/>
- <bean-property-setter-rulepattern="no"propertyname="no"/>
- <bean-property-setter-rulepattern="caption"propertyname="caption"/>
- <set-next-rulemethodname="addChapter"/>
- </pattern>
- <set-next-rulemethodname="addBook"/>
- </pattern>
- </digester-rules>
解析xml类的代码,修改为:
- publicclassMainTest{
- publicstaticvoidmain(String[]args){
- try{
- Digesterdigester=DigesterLoader.createDigester(DigesterXmlRuleTest.class.getResource("books-rule.xml"));
- Librarylibrary=(Library)digester.parse(DigesterXmlRuleTest.class.getResourceAsStream("books.xml"));
- System.out.println("图书馆:"+library.getName());
- System.out.println("共藏书:"+library.getBookList().size()+"本");
- System.out.println("*****************************");
- for(Bookbook:library.getBookList()){
- System.out.println("书名:"+book.getTitle()+"作者:"+book.getAuthor());
- System.out.println("------------------------------");
- System.out.println("共"+book.getChapters().size()+"章");
- for(Chapterchapter:book.getChapters()){
- System.out.println(chapter.getNo()+":"+chapter.getCaption());
- }
- System.out.println("------------------------------");
- }
- }catch(IOExceptione){
- e.printStackTrace();
- }catch(SAXExceptione){
- e.printStackTrace();
- }
- }
- }
用于规则放在xml文件中,所以解析的类,显得更加简洁一些。 (编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|