Digester:一个通用xml引擎的设计剖析

   一:Digester介绍

   Digester是Jakarta 子项目Commons下的一个模块,支持基于规则的对任意XML文档的处理。它最初是Structs项目的

一部分,后因其通用性而划归Commons.

   本文不是描述Digester如何使用,而是深入分析Digester的源码,对其设计进行分析,从而从中学到设计方法和一些设计

理念,正所谓“授人鱼,不如授人以渔”。

 

   二:不好的设计

  Digester要解决的问题看起来很简单:根据xml文件定义,来生成指定的对象。估计大部分人的第一反应就是if-else,由于

xml类似是树形结构的,因此为了完成一个xml文件的解析,需要if-else加上递归才能完成一个xml文件的解析,例如下面的

xml文件,于下面的写法:

                                                if( element = "book")

                                                {

                                                      processBook();

                                                 }

 

                                                if( element = "name ")

                                                {

                                                      processName();

                                                 }

                                                 .....................................

 

    从功能上来说,这样也确实是能够实现功能,但从设计角度来说,这样几乎是没有任何设计,为什么呢?

    这样的设计存在的主要问题如下:

    1)代码和xml结构和元素绑定,一旦xml结构变化,或者element的处理变化,解析代码就需要跟着调整;

    2)由于上面问题,导致这个所谓的xml引擎无法被重用,每个不同的项目采用不同的xml文件,都需要重新编写代码。

    总结来说,这个设计就是没有任何封装,无法重用,不能适应任何变化。

 

   三:Digester设计分析

    下面我们看看Digester是如何设计的。

    通过上面的一个样例分析,我们知道设计一个通用xml引擎要面临的设计问题有:

(1)xml文档格式不定;(2)每个xml对象的处理方式是可以变化的。

  那么,Digester是如何解决这两个问题呢?

 

  我们首先来看Digester的运行机制,如下是Digester的类结构图:

  

    

 

 

1)  首先,Client需要创建一个Digester对象;

2)  然后,Client必须根据自己的xml格式来添加所有的Rule。

3)  添加完Rule后,Client调用Digester的parse操作来解析xml文件。

4)  Digester实现了SAX的接口,解析时遇到具体的xml对象时会调用starElement等接口函数

5)  在这些SAX接口函数中,会扫描规则链rules(图中的RulesBase对象),找到匹配规则,规则匹配一般都是根据具体的元素名称来进行匹配。

6)  找到对应的rule后,依次执行rule。这里starElement对应的是begin操作,endElement对应的是end操作。具体要

    做的事情都在每个rule的begin、body、end函数中。

7)  文档结束后,会执行所有rule的finish函数。

 

从以上的运行过程可以看出,Digester为了解决面临的两个问题,采用了巧妙的设计方法:

(1)xml格式变化:Digester把这个变化抛给具体用户去解决,用户在使用Digester之前必须自己根据自己的

xml文件格式来构造规则链,Digester只提供构造规则链的手段,体现了有所为有所不为的设计思想。

(2)“处理方式变化”的问题,Digester将“处理方式”抽象为“规则rule”,一个规则对应一个处理方式。

Digester提供了通用的缺省的Rule,如果用户觉得Digester提供的规则不满足自己的要求,可以自己另外定制,样例

dbinsert就体现了这种情况。

 

有了以上的设计,Digester完全就是一个通用的xml引擎了,只要你根据自己的应用写对应的Rule就OK了,

个人想到的应用有(以下仅为推测,没有真正考核过是否是这样实现):

1)根据xml文件创建对象:例如struts,Android中由xml定义view;

2)根据xml文件执行操作:例如Ant,数据库操作;

3)根据xml文件定义流程:例如数据流、业务流处理;

........................(其它请大家自己发散了:-P)

 

四:Digester设计总结

    大部分人可能都知道设计模式中两个重要的设计原则“基于接口编程”和“封装变化”,但实际应用中如

体现呢?Digester为我们提供了很好的样例。

(1)基于接口编程:Digester的框架类都是接口或者虚类,例如Rules、Rule;

(2)封装变化:将具体的处理抽象为Rule,将xml的结构由用户去构造(因为这个无法抽象)。

顺便翻了一下《设计模式》,觉得Digester这种设计方法对应设计模式中的“策略模式”。

 

附:Digester源码CSDN上就有。

 

  

 

时间: 2024-11-02 19:56:25

Digester:一个通用xml引擎的设计剖析的相关文章

android通用xml解析方法_Android

1.为什么需要写一个通用xml解析方法. 当需要解析不同的xml节点.你有可能是在xml解析的时候匹配不同节点并且节点名都是写死的,这样的话你解析不同的节点就需要不同的解析方法.当然这种方式是最简单也是最笨的方法.为了减少代码把代码写得更有质量那么你就需要考虑设计一个通用的xml解析方法. 2.解析思路. 一般情况下,xml的解析结果最好放在一个实体类对象中,那样的话你使用起来非常方便(当然也更OO了),你也可以选择其他的方法把解析结果保存下来,不过个人觉得这种方式是比较好的.在解析过程中你需要

设计并实现用于ASP.NET一个通用的数据存取层应用程序

asp.net|程序|设计|数据 Designing and implementing a versatile data access tier for an ASP.NET applicationBy Paul Abarham In this article, we will drill down deeper in to the design of a n-tier architecture and our focus will be on the data access tier (DAT

dao-关于如何设计一个通用DAO和验证框架 及几个问题

问题描述 关于如何设计一个通用DAO和验证框架 及几个问题 工作中遇到的几个问题,自己不太有把握,请大家不吝赐教,可以讨论,非常着急,最好能有比较详细的代码,在此万分感谢了!! 在JavaEE的开发中,一个比较好的做法是采用通用的DAO,其中包含类似 save.delete.findXXX.countXXX之类的方法. 请设计和编写一个通用DAO,它继承自Hibernate, 其中包含delete. findById. findByExample.countByExample等方法. 其中 fi

做一个通用的XML序列化,支持所有类型

小知识:typeof(类型名)和实例.GetType()是什么? typeof(类名):返回直指的System.Type对象,并可以通过Type对象访问基类及本类一些信息 GetType():是object类下实例方法,即无论是自己定义的类还是.net框架类都可以用此方法 如果想返回String类型的全类型形式,可以用typeof(String) 如果想返回对象string a=null;中实例a的类型,可以用a.GetType() #region XML序列化 public static vo

换个视角看 Maven:一个领域平台的优美设计

作为一个Java程序员,Maven是再熟悉不过的工具了, 它提供了构建项目的一个框架, 在默认情况下为我们提供了许多常用的Plugin,其中便包括构建Java项目的Plugin,还有War,Ear等.除此之外还提供内建的项目生命周期管理. 以上是我们最熟悉的maven的一面. 下面我们要从领域平台设计的角度,分析Maven的优美设计,为我们做领域平台化提供参考,最后我们再来思考如何做招商的领域平台. Maven是领域驱动设计实现的,作为一个强大的项目管理构建平台而实现 我们先会介绍maven的基

写一个通用的代码生成器

       代码生成器对于JAVA码农来说并不陌生.在一些业务性比较强,但编码比较规范的项目中,往往会有大量的重复或者类似的代码要写.比如对表的增删改查,比如生成用于远程调用的客户端方法存根等等.面对这种情况,程序员通常的做法就是拿一个现成模块的代码copy过来再改改.于是,为了避免这种低效而容易出错的编码方式,诞生了各种各样的能跟据当前项目特证自动生成代码的代码生成器程序.这种程序的本质上就是将大量重复的复制修改工作用程序自动来做,以便自动产生适合自己项目的代码.        然而,这种代

GraphQL 用例:使用 Golang 和 PostgreSQL 构建一个博客引擎 API

摘要 GraphQL 在生产环境中似乎难以使用:虽然对于建模功能来说图接口非常灵活,但是并不适用于关系型存储,不管是在实现还是性能方面. 在这篇博客中,我们会设计并实现一个简单的博客引擎 API,它支持以下功能: 三种类型的资源(用户.博文以及评论)支持多种功能(创建用户.创建博文.给博文添加评论.关注其它用户的博文和评论,等等.) 使用 PostgreSQL 作为后端数据存储(选择它因为它是一个流行的关系型数据库). 使用 Golang(开发 API 的一个流行语言)实现 API. 我们会比较

j661 0.51.3发布 一个通用CDS服务

j661项目提供了一个通用的CDS服务(或ARINC661服务器),执行ARINC661标准,原型ARINC661的概念和架构,以及方便的ARINC661规范和项目之间的重用.CDS的架构设计以便确定服务器的行为,可以很容易地修改或扩展.这是实现模块化插件架构,允许在不改变服务器核心进行定制. j661 0.51.3该版本修复了高负荷工作量导致的一个错误,当一个以上的沟通渠道定义在网络配置的XML文件中,这将导致高负载工作量的异常.修复了服务器未能找到资源(字体或图像)的问题,其路径包含服务器图

j661 0.52 Beta 1发布 一个通用CDS服务

j661 0.52 Beta 1该版本完全加载了二进制或XML定义文件属性,在编辑器中修改了大小/长度和最大大小.修复了几个小部件事件定义问题.修复了一些在游标执行的问题.重组的代码在服务器中删除了多个关键部分(同步方法).修复了某些情况下加速时将不被更新正确的插件. j661项目提供了一个通用的CDS服务(或ARINC661服务器),执行ARINC661标准,原型ARINC661的概念和架构,以及方便的ARINC661规范和项目之间的重用.CDS的架构设计以便确定服务器的行为,可以很容易地修改