`

关于struts框架中的xml解析

    博客分类:
  • XML
阅读更多
degister In Action (xml解析)
引言

  前前后后,研究struts 的框架源代码,也有几回了,一直没有找到其解析XML 配置文件的代码 =.= !,其实是被误导了(想当然的以为它会用DOM4j或JDOM),前几天,又拿来struts的源码来跟,发现了些端倪.就仔细研究了一下,意外发现了一个很好用的解析XML的东西,即org.apache.common.digester 包.
 在网上求证了一下,发现原本digester 包是和Struts一起发布的,原来只是为了解析struts-config.xml配置文件而设计的,后来发现这个包解析xml很通用,也很好用,于是,放到了commons库中.笔者小试了一下,发现果然方便,它可以直接将XML文档转换成对象,它的目标是以尽可能简单的方式把xml文件转换成对象,思想上有点类似ORM,也许以后可以起个名字叫OXM(object-xml-mapping)在本文中,也将采用OXM这个词汇.
   
 
      注:本文不适合java以及struts初学者阅读,读者最好有通过SAX或DOM解析XML的经验,的经,以便更好的理解..

CH.1   digester   小窥


这一章是一个小的示例,用来像大家展示使用digester来解析xml的基本的流程.以及,使用digester来进行了xml解析是多么的简洁和简单. 本节的示例不要求你能马上读懂,在以后的章节我还会对每个类进行更详细的讲解.
好吧,让我们开始我们的digester之旅.



1.1  一个简单的xml解析示例

首先,在项目中导入commons-digester.jar包以及关联包commons-collections.jar ,commons-beanutils.jar ,commons-logging.jar.
 


然后,建立一个要解析的名为simple.xml的xml文档 代码如下.

Xml代码
<?xml version="1.0" encoding="UTF-8"?> 
<person  name="7upcat"  age="24"> 
  <address>深 圳 市 下 梅 林 </address> 
</person> 

<?xml version="1.0" encoding="UTF-8"?>
<person  name="7upcat"  age="24">
  <address>深 圳 市 下 梅 林 </address>
</person>


接着,建立,一个同这个xml文档进行映射的pojo类.
Java代码
package com.zhengzm.prj.digester;  
 
/** 
*  
* @author 7upCat 
*  
*/ 
public class Person {  
 
private String age;  
private String name;  
private String address;  
 
public String getAge() {  
return age;  
}  
 
public void setAge(String age) {  
this.age = age;  
}  
 
public String getName() {  
return name;  
}  
 
public void setName(String name) {  
this.name = name;  
}  
 
public String getAddress() {  
return address;  
}  
 
public void setAddress(String address) {  
this.address = address;  
}  
 
}  
 
 
解析代码如下.  
 
 
package com.zhengzm.prj.digester.simple_example;  
 
import java.io.File;  
import java.io.IOException;  
 
import org.apache.commons.digester.Digester;  
import org.xml.sax.SAXException;  
 
public class TestDigester {  
 
      
      
    public static void main(String[] args) throws IOException, SAXException {  
          
        //创建解析对象digester  
         Digester  digester=new Digester();  
         //为digester对象填加解析规则  
         digester.addObjectCreate("person/", Person.class);  
         digester.addSetProperties("person/");  
         digester.addBeanPropertySetter("person/address","address");  
         //解析xml文档返回Person对象.  
         Person o=(Person)digester.parse(new File("simpleXml.xml"));  
         //输出这个对象的值  
                  System.out.println("the person is "+ o.getName() );  
               System.out.println("she/he is"+ o.getAge()+"years old");  
               System.out.println("she/he lives in "+o.getAddress());  
    }  


package com.zhengzm.prj.digester;

/**
*
* @author 7upCat
*
*/
public class Person {

private String age;
private String name;
private String address;

public String getAge() {
return age;
}

public void setAge(String age) {
this.age = age;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getAddress() {
return address;
}

public void setAddress(String address) {
this.address = address;
}

}


解析代码如下.


package com.zhengzm.prj.digester.simple_example;

import java.io.File;
import java.io.IOException;

import org.apache.commons.digester.Digester;
import org.xml.sax.SAXException;

public class TestDigester {



public static void main(String[] args) throws IOException, SAXException {

//创建解析对象digester
Digester  digester=new Digester();
//为digester对象填加解析规则
digester.addObjectCreate("person/", Person.class);
digester.addSetProperties("person/");
digester.addBeanPropertySetter("person/address","address");
//解析xml文档返回Person对象.
Person o=(Person)digester.parse(new File("simpleXml.xml"));
//输出这个对象的值
                  System.out.println("the person is "+ o.getName() );
               System.out.println("she/he is"+ o.getAge()+"years old");
               System.out.println("she/he lives in "+o.getAddress());
}
}

控制台输出结果如下:

the person is 7upcat
she/he is24years old
she/he lives in 深 圳 市 下 梅 林



我们看到simple.xml文档被解析后直接生成了一个Person对象,然后我们就可以直接对Person对象进行操作..
其它的xml解析方式,无论是SAX,还是DOM,都无法直接做到这点(其实digester是对SAX的简单封装),并且,Struts的配置文件是由degister来解析的, 它在实际应用中.表现也很稳定.
     
       其实这一章可以写一下,其实的很多种解析xml的工具的代码,来分别和digester进行比较一下.但是时间实在是有限(=.= !  要上班ING).,就不一一列举了.
       下一章我们将介绍digester中的核心类Digester 和Rule  的api.以及digester的实现相制.
    


CH2.   digester  API   introduction   (好像名字有点大咧  )



这一章将介绍digester中的两个核心的类Digester 以及Rule并,让你明白digester的实现机制,当然,暂时不打算从源代码级别讲起,因为那个太花精力,而且,我们主要是学如何使用它(这符合XP思想?  其实可能只是作者太忙了没有时间专门去研究 ^^) 

2.1   Digester类.

  digester包中最重要的类就是Digester了.整个解析过程实际上就是通过调用这个对象的 java.lang.Object parse(java.io.File file)   方法来进行的,这个方法的返回值是所解析xml文档的根元素对应的对象,它还包括很多个重载版本,参数分别可以接受,InputStream,java.io.Reader,java.net.URL,等.
                 

  org.xml.sax.helpers.DefaultHandler
        |
        +--org.apache.commons.digester.Digester


由上面的继承结构可以看出,Digester是DefaultHandler的子类,可以推断出digester 包实际上是对SAX  api的简单封装, 我们知道SAX解析XML是基于事件的,那当然,在digester中也是如此.整个解析过程将触发一系列事件,然后我们通过处理这些事件来完成我们的工作.
下面我们就使用Digester来解析一个XML文档吧.


在项目中建立person.xml如下:

Xml代码
<?xml version="1.0" encoding="UTF-8"?> 
<person name="7upCat" age="24"> 
   <address city="深 圳 " street="梅 林 ">   
   </address> 
   <friend name="vincent"></friend> 
   <friend name="鱼 生 烟 "></friend>         
</person> 

<?xml version="1.0" encoding="UTF-8"?>
<person name="7upCat" age="24">
   <address city="深 圳 " street="梅 林 ">
   </address>
   <friend name="vincent"></friend>
   <friend name="鱼 生 烟 "></friend>      
</person>




从这个XML文件中可以看出,对于每个person 都会有 name和age两个属性,并且,每个person节点都会有多个friends子节点,有一个address子节点.
    我们的目标是,通过解析上面的XML文件,得到一个Person对象,并且这个对象中包含多个Friend对象的集合,一个Address对象.





接着,建立需要做 OXM的 pojo (plain old java object)类(^^相信,如果读者有用过hibernate的经验应该可以很容易理解).
     注: pojo  就是符合javabean规范的普通的java对象.(含setter getter)



Person 类.
Java代码
 
package com.zhengzm.prj.digester.ch2.pojo;  
 
import java.util.Vector;  
 
/** 
* 每 一 个 person中 包 含 了 ,这 个 人 的 名 字 ,年 龄 ,居 住 地 址 address对 象 ,朋 友 的 集 合 friends 
*  
* @author 7upCat 
*  
*/ 
public class Person {  
private String name;  
private String age;  
public Address address;  
 
 
 
 
/** 
* friends 对 象 的 集 合 . 
*/ 
 
public Vector<Friend> friends = new Vector<Friend>();  
 
public void addFriend(Friend f) {  
friends.addElement(f);  
}  
 
public Vector<Friend> getFriends() {  
return friends;  
}  
 
public void setFriends(Vector<Friend> friends) {  
this.friends = friends;  
}  
 
public Address getAddress() {  
return address;  
}  
 
public void setAddress(Address address) {  
this.address = address;  
}  
 
public String getName() {  
return name;  
}  
 
public void setName(String name) {  
this.name = name;  
}  
 
public String getAge() {  
return age;  
}  
 
public void setAge(String age) {  
this.age = age;  
}  
 
@Override 
public String toString() {  
StringBuffer sb = new StringBuffer();  
sb.append("这 个 家 伙 名 叫 " + this.name + "今 年 " + this.age + "岁 了 ");  
sb.append("\n");  
sb.append("他 /居 住 在 :  " + address.toString());  
sb.append("\n");  
sb.append("他 /她 的 朋 友 是 :");  
for (Friend friend : friends) {  
sb.append(friend.getName());  
sb.append("  ");  
}  
return sb.toString();  
 
  }  
 



package com.zhengzm.prj.digester.ch2.pojo;

import java.util.Vector;

/**
* 每 一 个 person中 包 含 了 ,这 个 人 的 名 字 ,年 龄 ,居 住 地 址 address对 象 ,朋 友 的 集 合 friends
*
* @author 7upCat
*
*/
public class Person {
private String name;
private String age;
public Address address;




/**
* friends 对 象 的 集 合 .
*/

public Vector<Friend> friends = new Vector<Friend>();

public void addFriend(Friend f) {
friends.addElement(f);
}

public Vector<Friend> getFriends() {
return friends;
}

public void setFriends(Vector<Friend> friends) {
this.friends = friends;
}

public Address getAddress() {
return address;
}

public void setAddress(Address address) {
this.address = address;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getAge() {
return age;
}

public void setAge(String age) {
this.age = age;
}

@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("这 个 家 伙 名 叫 " + this.name + "今 年 " + this.age + "岁 了 ");
sb.append("\n");
sb.append("他 /居 住 在 :  " + address.toString());
sb.append("\n");
sb.append("他 /她 的 朋 友 是 :");
for (Friend friend : friends) {
sb.append(friend.getName());
sb.append("  ");
}
return sb.toString();

  }

}



Friend 类

Java代码
package com.zhengzm.prj.digester.ch2.pojo;  
 
 
/** 
*  
* @author 7upCat 

*/ 
public class Friend {  
 
private String name;  
 
public String getName() {  
return name;  
}  
 
public void setName(String name) {  
this.name = name;  
}  
 
@Override 
public String toString() {  
return    name;  
}  
 


package com.zhengzm.prj.digester.ch2.pojo;


/**
*
* @author 7upCat
*
*/
public class Friend {

private String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@Override
public String toString() {
return    name;
}

}



Address 类

Java代码
package com.zhengzm.prj.digester.ch2.pojo;  
 
 
/** 
*  
* a address  object contaions   the  name of  the  city and  the name of the street 
*   
* @author 7upCat 

*/ 
public class Address {  
 
private String city;  
private String street;  
 
public String getCity() {  
return city;  
}  
 
public void setCity(String city) {  
this.city = city;  
}  
 
public String getStreet() {  
return street;  
}  
 
public void setStreet(String street) {  
this.street = street;  
}  
 
@Override 
public String toString() {  
   
return  city+"市 ,"+street+"\n";  
}   
 


package com.zhengzm.prj.digester.ch2.pojo;


/**
*
* a address  object contaions   the  name of  the  city and  the name of the street

* @author 7upCat
*
*/
public class Address {

private String city;
private String street;

public String getCity() {
return city;
}

public void setCity(String city) {
this.city = city;
}

public String getStreet() {
return street;
}

public void setStreet(String street) {
this.street = street;
}

@Override
public String toString() {

return  city+"市 ,"+street+"\n";
}

}
准备工作终于完成,解析的代码如下所示

Java代码
Digester  digester=new Digester();  
Person person=(Person)digester.parse(new File("person.xml"));  
System.out.println(person); 

Digester  digester=new Digester();
Person person=(Person)digester.parse(new File("person.xml"));
  System.out.println(person);

运行,结果为null 为什么呢? 结果不应该是Person对象吗?    请读者回忆一下我们刚才做过的事情.
      1.写了一个person.xml的xml文件.
      2.写了一组和person.xml做映射的pojo.  
      3.解析xml文档.

   : )   似乎少了点什么吧.大家不妨想想做ORM的时候,  我们做过的步骤.
         1.建立数据库表.
         2.写一组同这些数据库表做映射的pojo.
         3.添写,将这些pojo同数据库表关联起来的配置文件(可能是xml,也可能是properties文档).
         4.对pojo对象进行数据库操作.


   细心的读者一定发现了,在我们解析xml文档的时候少了哪一步骤, 我们并没有把xml文件,同pojo以某种形式关联起来,于是,理解应当我们解析的时候并没有产生相应的Object ..
   可在digester中xml文档,同pojo 是如何关联起来的呢? 在digester中实际上是通过监听器来实现这个的,下面一节我们将介绍Rule类,以及它的子类.并为Digester对象添加监听器.
   
  




2.2  Rule类以及digester世界中的pattern.


    Rule是digester世界中的监听器的抽象基类,  由于,Rule是抽象类,不能被实例化,所以你要使用Rule的时候必需继承它,并覆盖相应的方法.Digester则是被监听对象,如果你不为你的Digester对象,来注册监听,那么解析xml文档中的所有事件都将全部被忽略.
     Rule类一共声明了3个方法,如果,每个方法都有一个namespace 敏感的重载版本.(注一)

  void begin(Attributes attributes)
解析时遇到符合pattern匹配规则的文档的xml的节点时被调用.
  void body(String text)
解析时遇到符合pattern匹配规则的文档的xml的节点的值时被调用,并将这个值做为参数传递给方法.如果这个节点没有值,这个方法也会被调用,并将 null做为调用参数
  void end()
解析时遇到符合pattern匹配规则的文档的xml的节点结束时被调用. 


注一: 所谓的namespace敏感的重载版本实际上说的意思是,当Digester对象通过,  setNamespaceAware(boolean namespaceAware) 方法设置为true的时候,那么,将会调用.重载版本的方法,而不是上面的3个方法.


 
例如下面这个SimpleRule就是覆盖了Rule的begin方法, 并简单向控制台输出信息.

Java代码
package com.zhengzm.prj.digester.simple_example;  
 
import org.apache.commons.digester.Rule;  
import org.xml.sax.Attributes;  
 
/*** 
* 一 个 简 单 的 Rule实 现 ,仅 向 控 制 台 输 出 一 句 话 / 
* @author 7upCat 

*/ 
public class SimpleRule  extends Rule {  
 
 
   
@Override 
public void begin(Attributes attributes) throws Exception {  
System.out.println(" begin countered");  
   
}  
 
@Override 
public void body(String namespace, String name, String text)  
throws Exception {  
System.out.println("body endcountered ");  
}  
 
@Override 
public void end() throws Exception {  
System.out.println("end countered");  
}  


package com.zhengzm.prj.digester.simple_example;

import org.apache.commons.digester.Rule;
import org.xml.sax.Attributes;

/***
* 一 个 简 单 的 Rule实 现 ,仅 向 控 制 台 输 出 一 句 话 /
* @author 7upCat
*
*/
public class SimpleRule  extends Rule {



@Override
public void begin(Attributes attributes) throws Exception {
System.out.println(" begin countered");

}

@Override
public void body(String namespace, String name, String text)
throws Exception {
System.out.println("body endcountered ");
}

@Override
public void end() throws Exception {
System.out.println("end countered");
}
}

   我们通过,  Digester对象的  addRule(java.lang.String pattern, Rule rule)方法,来为它注册监听器. 参数pattern是匹配的规则.在digester中,是以嵌套的标签名称以“/“相连接来做为匹配规则的. 以2,1中的person.xml文件为例.
Xml代码
<?xml version="1.0" encoding="UTF-8"?> 
<person name="7upCat" age="24"> 
   <address city="深圳" street="梅林">   
   </address> 
  <friend name="vincent"   age="24" ></friend> 
<friend name="鱼生烟"     age=“23“></friend>         
</person> 

<?xml version="1.0" encoding="UTF-8"?>
<person name="7upCat" age="24">
   <address city="深圳" street="梅林">
   </address>
  <friend name="vincent"   age="24" ></friend>
<friend name="鱼生烟"     age=“23“></friend>      
</person>


"person/“ 将同<person>标签匹配
"person/address/“   同<address>标签匹配
"person/friend/“   同<friend>标签匹配

    

我们现在先把这个SimpleRule注册给Degister 对象,然后再来解析一下,person.xml看看会出现什么情况呢?
Java代码
Digester  digester=new Digester();  
digester.addRule("person/",new SimpleRule() );  
Person o=(Person)digester.parse(new File("person.xml"));  
System.out.println("the person is "+ o );  
         

Digester  digester=new Digester();
digester.addRule("person/",new SimpleRule() );
Person o=(Person)digester.parse(new File("person.xml"));
System.out.println("the person is "+ o );

输出结果是:

begin countered
body endcountered
end countered
the person is null


我们看到, SimpleRule中的方法均被调用了.然而,我们的Person对象依然没有被创建.不要灰心,现在你已经明白了,digester包实现的基本原理,   Degister类通过继承org.xml.sax.helpers.DefaultHandle来监听使用SAX来解析XML文档时发生的事件,并对事件产生的数据进行了包装,然后调用注册在Degister中相匹配的Rule的子类的方法.对数据进行进一步封装.
   下一章,我们将介绍一些Degister中一些十分有用的方法,和一些由digester包提供好的Rule的实现 .
分享到:
评论

相关推荐

    Dom4j解析struts2框架的struts.xml

    Dom4j解析struts2框架的struts.xml,自定义struts框架需要解析配置文件

    自定义类似struts的mvc框架

    自定义类似struts的mvc框架,有struts1和struts2的共同特点

    Struts框架

    Struts1.0和1.1差别很大,主要有两点:Struts1.1中引用了很多apache其他项目的类包,如:xml解析、日志、验证等,因此struts1.1的包结构与1.0完全不同。在struts1.1环境下,一个webapp要成功运行,除了struts.jar外...

    开发自己一套struts框架

    此项目是为了更深入的理解MVC模式以及Struts的工作流程而开发的,运用了第三方commons组件, commons-digester来解析xml文件,把配置信息全部封装成类,然后运用MVC的思想去做相应的操作.

    struts2 validation.xml 验证规则代码解析

    主要介绍了struts2 validation.xml 验证规则代码解析,具有一定借鉴价值,需要的朋友可以参考下

    struts培训课件

    第一部分 Struts的优势 第二部分 Struts框架与MVC 第三部分 Struts工作流程 第四部分 Struts-config.xml的配置文件解析 第五部分 Struts中错误处理 第六部分 Struts实例操作

    servelt模拟struts1框架

    使用servlet模拟struts1的工作原理,解析xml,处理请求,自动封装数据

    Struts2的struts.xml配置详细介绍

    配置常量,可以改变Struts 2框架的一些行为 name属性表示常量名称,value属性表示常量值 package元素: 包的作用:简化维护工作,提高重用性 包可以“继承”已定义的包,并可以添加自己包的配置 name属性为必须去且...

    struts2学习教程

    struts2学习教程包括:第一个Struts2程序,处理一个form多个submit,struts.xml常用配置解析,使用validate方法验证数据,使用Validation框架验证数据,在Action类中获得HttpServletResponse对象的四种方法,上传...

    Servlet简单模拟Struts2

    用sevrlet模拟Struts2的简单功能。从拦截请求、解析自定义xml数据文件以及动态生成action的代理去执行目标方法,并实现了简单的日志拦截【interceptor】

    使用Struts的Action来对数据库进行增、删、改、查四项操作(源码)

    使用Struts的Action来对数据库进行增、删、改、查四项操作 &lt;br/&gt;1、数据库MySQL,创建数据库 Pagination MySQL.sql用来创建表结构 &lt;br/&gt;连接方式有两种,一种直接JDBC,一种通过连接池,代码中有说明...

    Struts培训word

    第一部分 Struts的优势 第二部分 Struts框架与MVC 第三部分 Struts工作流程 第四部分 Struts-config.xml的配置文件解析 第五部分 Struts中错误处理 第六部分 Struts实例操作

    EFS+Struts2实战之grid Pane 解析XML实现数据交换

    讲解如何用EFS前台框架实现和后台数据交换 原创教程 欢迎交流

    搞定J2EE:STRUTS+SPRING+HIBERNATE整合详解与典型案例 (1)

    12.6.15 编写Struts的配置文件struts-config.xml 12.6.16 编写Spring和Hibernate的配置文件spring-config.xml 12.6.17 编写web.xml 12.6.18 验证示例 12.7 小结 第四篇 J2EE项目案例精选 第十三章 网上调查系统 13.1...

    SSH的jar包.rar

    一个请求在Struts2框架中的处理大概分为以下几个步骤: 1、客户端初始化一个指向Servlet容器(例如Tomcat)的请求 2、这个请求经过一系列的过滤器(Filter)(这些过滤器中有一个叫做ActionContextCleanUp的可选...

    搞定J2EE:STRUTS+SPRING+HIBERNATE整合详解与典型案例 (3)

    12.6.15 编写Struts的配置文件struts-config.xml 12.6.16 编写Spring和Hibernate的配置文件spring-config.xml 12.6.17 编写web.xml 12.6.18 验证示例 12.7 小结 第四篇 J2EE项目案例精选 第十三章 网上调查系统 13.1...

    基于Ajax的新MVC框架的研究与实现

    与使用传统的XML格式或者JSON格式相比,新的树结构信息表示法将占用更少的存储空间,获得更高的解析效率。新框架的请求处理流程借鉴了JSF的请求生命周期,但对它进行了改造,从而简化了流程。本文还将Java反射机制与...

    Struts+Spring+Hibernate整合详解与典型案例源代码.

    工具详尽:包括JDK、Tomcat、Eclipse、MySQL、Log4j、Ant、JUnit、CVS、解析XML文件等; 由浅入深:每章从简单示例入手,最后给出一个详细示例加深理解; 实战性强:书中提供了大量典型的应用案例,实战性很强; ...

    搞定J2EE:STRUTS+SPRING+HIBERNATE整合详解与典型案例 (2)

    12.6.15 编写Struts的配置文件struts-config.xml 12.6.16 编写Spring和Hibernate的配置文件spring-config.xml 12.6.17 编写web.xml 12.6.18 验证示例 12.7 小结 第四篇 J2EE项目案例精选 第十三章 网上调查系统 13.1...

    Java的Struts框架中append标签与generator标签的使用

    append 标签: 这些append标签需要两个或两个以上的列表作为参数,并追加它们放在一起,如下图所示: 如果有两个列表A和B的值A1,A2和B1,

Global site tag (gtag.js) - Google Analytics