新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   XML论坛     W3CHINA.ORG讨论区     计算机科学论坛     SOAChina论坛     Blog     开放翻译计划     新浪微博  
 
  • 首页
  • 登录
  • 注册
  • 软件下载
  • 资料下载
  • 核心成员
  • 帮助
  •   Add to Google

    >> 本版讨论DOM, SAX, XPath等。
    [返回] 中文XML论坛 - 专业的XML技术讨论区XML.ORG.CN讨论区 - XML技术『 DOM/SAX/XPath 』 → [原创]对XML文档操作的通用CRUD(JDOM版) 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 9604 个阅读者浏览上一篇主题  刷新本主题   树形显示贴子 浏览下一篇主题
     * 贴子主题: [原创]对XML文档操作的通用CRUD(JDOM版) 举报  打印  推荐  IE收藏夹 
       本主题类别:     
     jomper 帅哥哟,离线,有人找我吗?
      
      
      等级:大一(猛啃高等数学)
      文章:18
      积分:168
      门派:XML.ORG.CN
      注册:2004/8/23

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给jomper发送一个短消息 把jomper加入好友 查看jomper的个人资料 搜索jomper在『 DOM/SAX/XPath 』的所有贴子 引用回复这个贴子 回复这个贴子 查看jomper的博客楼主
    发贴心情 [原创]对XML文档操作的通用CRUD(JDOM版)

    /**
    *1.操作XML文档分析
    *2.设计过程
    *3.适用范围
    */


    关键词:元组元素 元组元素相当于关系数据库里元组的概念。

    1.0 操作XML文档分析
    1.1 为什么要写XML文档操作的通用CRUD(Create Read/Retrieve Update Delete)。
    做过几次读写改删XML文档的工作,总是被大量的element构建弄的头晕眼花。XML文档简单点还好,一旦元素属性变得复杂,整个XMLDAO模块就会变的相当臃肿。导致程序的可读性下降,bug增多。而且每个XMLDAO的CRUD都是做的同一个流程,完全可以独立出来。

    1.2 XMLDAO的CRUD分析
    在XML的CRUD操作中有几个功能是会反复重复的。
    (1)Input:读XML文档,并用SAX或者DOM解析成Document对象。
    (2)Find:用XPath在文档中查询元素,并返回查询结果。其实在操作XML数据的时候Find跟Read基本是一个概念,查询数据后当然是要返回一个查询结果的,不然好浪费资源。这里结果就是一个list。
    (3)Construts:构建需要操作的Element。包括构建新元素,更新元素或属性的值,删除元素。为什么不是Document对象?其实没什么区别。
    (4)Output:写Document对象到XML文档。

    唯一有区别的地方是Construts Element。对于不同的XML文档存在着不同Element上下文。我要做的就是把除Construts Element之外的工作独立出来。

    Create操作 需要Construts Element和输出Document。
    Read操作 需要读取XML文档,并返回一个读取结果。
    Retrieve操作 需要读取XML文档并给特定的Element添加一个子元素。一般这个特定的元素就是元组元素的父亲。元组元素相当于关系数据库里元组的概念。
    Update操作 需要读取XML文档,然后通过XPath获得查询结果并重新构建这个结果。最后输出到文档。
    Delete操作 需要读取XML文档,然后通过XPath获得查询获得需要删除元素。最后在上下文中删除它。

    下面是每个操作的工作流程:
                     Create     Read      Retrieve      Update     Delete
    Input                      √           √              √         √
    Find                       √           √              √
    Construts         √                    √              √
    Output            √                    √              √

    2.0 设计过程
    2.1 XML文档设计(XML文档设计的一点建议)
    2.1.1 建议一 尽量少用elements来装载数据,无论什么时候都尽可能用attributes来代替
    根据《Java Enterprise Best Practices》- 5.1.3 Use Elements Sparingly, Attributes Excessively的内容,“ use elements infrequently and, instead, use attributes whenever possible. ”尽量少用elements来装载数据,无论什么时候都尽可能用attributes来代替。这样做的好处是针对SAX的处理机制做出了优化。可能你要说你从不使用SAX,你有其他的解决方案例如:DOM,JAXP等等。事实上这些高层的API例如:DOM,JAXP,JDOM,SOAP在底层还是使用的SAX,如果你不相信你可以直接去看它们的源码。

    一个XML文档的例子:
    例2.1:
    <?xml version="1.0" encoding="UTF-8"?>
    <JomperWorld>
     <userInfo userCode="-1426920836">
      <accountInfo userId="jomper1" password="888888"></accountInfo>
      <basicInfo nickName="jo" gender="男" placeOfBirth="hubei" email="1@1.com" registerDate="3-17-2006" picture="null"></basicInfo>
      <detailInfo>
       <experienceOfTeaches><![CDATA[test12]]></experienceOfTeaches>
       <individualHonor><![CDATA[test22]]></individualHonor>
      </detailInfo>
     </userInfo>
    </JomperWorld>

    2.1.2 建议二 给你的元组元素确定一个KEY
    这样设计应当还注意一个问题,特别是你可能会使用XPath。
    就看例2.1,如果元组元素<userInfo/>没有一个userCode属性。那么已知accountInfo.userId想查询basicInfo.nickName 的XPath就必须这样写 "/JomperWorld/userInfo[accountInfo/@userId='jomper1']",但是得到的是<userInfo/>而不是期望的nickName属性。必须userInfo.getChild("basicInfo").getAttribute("nickName");才能获得nickName属性。
    当然这不会给设计带来致命的打击,但多少会有些不便,这个不便具体有多少只有你自己知道。

    2.2 Construts element类的设计

    2.2.1  Builder接口设计
    由于将给不同的XML文档构建元组元素,所以这个接口是通用XMLDAO的关键。
    需要Construts Element的操作包括create,retrieve,update。
    例2.2:
     public interface Builder {
      /** builderType */
      public static final int USER_INFO_BUILDER= 0;
      //更多的builderType......

      /**
      * create&retrieve构建元素
       * @param toggle create&add判断开关
       * @param facade elements外观
       * @return 元组元素
       */
      public Element addBuilder(boolean toggle,Object facade);
     
      /**
       * update构建元素
      * @param facade elements外观
      * @param mainElement 元组元素
       */
      public void updateBuilder(Object facade,Element mainElement);
     }
    builderType 是用来在XMLDAO里判断facade的对象类型。本来可以用instanceof做迭代判断最后确定其对象类型,但这样效率太低。于是传一个参数来确定。不知道还有没有更好的办法。
    facade 可以是一个元素的DTO(元组元素很简单的情况),也可以是几个元素DTO的外观。可以直接通过它获得element的数据,也可以通过它间接获得其他元素DTO的数据。


    2.2.2 ConcreteBuilder类的设计
    例2.3:
    public class UserInfoBuilder implements Builder{
     private Element rootElement,userInfoElement;
     
     UserInfoFacade userInfo;
     
     public UserInfoBuilder(){
      //初始化rooElement和元组Element(userInfoElement)
      elementDecorator = new ElementDecorator();
      rootElement = new Element(UserInfo.ROOT_ELEMENT);
      userInfoElement = new Element(UserInfo.USER_INFO_ELEMENT);
     }
     
     /**
      * 创建,添加元素构建器
      * @param toggle 开关 [true 添加][false 创建]
      * @param userInfo 用户信息
      * @return element [toggle:true 返回主元素][toggle:false 返回根元素]
      */
     public Element addBuilder(boolean toggle,Object userInfo){
      if(userInfo instanceof UserInfoFacade){
       this.userInfo = (UserInfoFacade)userInfo;
      }else{
       if (logger.isDebugEnabled()) {logger.debug("addBuilder() - UserInfoFacade 对象匹配失败");}
      }
      //具体Construts动作省略,详情请看源码
      
      return toggle ? userInfoElement : rootElement.addContent(userInfoElement);
     }
     
     /**
      * 更新文档元素
      * @param userInfo 用户信息
      * @param mainElement 主元素
      */
     public void updateBuilder(Object userInfo,Element mainElement){
      
      if(userInfo instanceof UserInfoFacade){
       this.userInfo = (UserInfoFacade)userInfo;
      }else{
       if (logger.isDebugEnabled()) {logger.debug("updateBuilder() - UserInfoFacade 对象匹配失败");}
      }
      // 具体更新动作省略,详情请看源码
     }
    }

    2.2.3 BuilderFactory

    public class BuilderFactory {
     private static final Logger logger = Logger.getLogger(BuilderFactory.class);
     
     public static Builder getBuilder(int builderType){

      switch(builderType){
       case Builder.USER_INFO_BUILDER :
        if (logger.isDebugEnabled()) {logger.debug("getBuilder() - 创建UserInfoBuilder实例完毕");}
        return new UserInfoBuilder();
       default:
        if (logger.isDebugEnabled()) {logger.debug("getBuilder() - 创建Builder实例失败");}
        return null;
      }
     }
    }

    这里用工厂来创建不同的Builder实例,起到ConcreteBuilder与XMLDAO解耦的效果。

    2.3 通用XMLDAO类的设计
    在这个类里一共有5个方法,它们将完成CRUD。(create、read、add、update、delete)
    2.3.1 create方法
     /**
      * 创建单个文档
      * @param file 目标输出文档路径
      * @param facade elements外观
      * @param builderType 获得构建器的类型
      */
     public void create(String file,Object facade,int builderType){
      doc = new Document();
      // Construts Element
      doc.addContent(BuilderFactory.getBuilder(builderType).addBuilder(false,facade));
      // Output
      OutputFactory.newJDOMOutput().outputXML(file,doc);
     }

    在这个方法里用BuilderFactory创建具体的UserInfoBuilder实例。

    该模块类图:

    此主题相关图片如下:
    按此在新窗口浏览图片

    待续...(3-22-2006)


    [此贴子已经被作者于2006-3-22 21:05:35编辑过]

       收藏   分享  
    顶(0)
      




    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2006/3/22 19:54:00
     
     SATOKO2006 帅哥哟,离线,有人找我吗?
      
      威望:1
      等级:大三暑假(ITELS考了7分!)
      文章:164
      积分:950
      门派:XML.ORG.CN
      注册:2005/12/5

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给SATOKO2006发送一个短消息 把SATOKO2006加入好友 查看SATOKO2006的个人资料 搜索SATOKO2006在『 DOM/SAX/XPath 』的所有贴子 引用回复这个贴子 回复这个贴子 查看SATOKO2006的博客2
    发贴心情 
    嗯,不错,关注中。。。。。。

    ----------------------------------------------
    MasterXML

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2006/3/23 11:23:00
     
     malcolm 帅哥哟,离线,有人找我吗?
      
      
      等级:大一新生
      文章:0
      积分:56
      门派:XML.ORG.CN
      注册:2006/3/23

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给malcolm发送一个短消息 把malcolm加入好友 查看malcolm的个人资料 搜索malcolm在『 DOM/SAX/XPath 』的所有贴子 引用回复这个贴子 回复这个贴子 查看malcolm的博客3
    发贴心情 
    mark
    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2006/3/23 12:55:00
     
     jomper 帅哥哟,离线,有人找我吗?
      
      
      等级:大一(猛啃高等数学)
      文章:18
      积分:168
      门派:XML.ORG.CN
      注册:2004/8/23

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给jomper发送一个短消息 把jomper加入好友 查看jomper的个人资料 搜索jomper在『 DOM/SAX/XPath 』的所有贴子 引用回复这个贴子 回复这个贴子 查看jomper的博客4
    发贴心情 
    能不能让我 编辑一下原来的帖子,不然这样好郁闷.

    2.3 通用XMLDAO类的设计
    在这个类里一共有5个方法,它们将完成CRUD。(create、read、add、update、delete)
    2.3.1 create方法
     /**
      * 创建单个文档
      * @param file 目标输出文档路径
      * @param facade elements外观
      * @param builderType 获得构建器的类型
      */
     public void create(String file,Object facade,int builderType){
      doc = new Document();
      // Construts Element
      doc.addContent(BuilderFactory.getBuilder(builderType).addBuilder(false,facade));
      // Output
      OutputFactory.newJDOMOutput().outputXML(file,doc);
     }

    在这个方法里用BuilderFactory创建具体的UserInfoBuilder实例,实例类型由builderType决定。
    然后根据facade完成具体的Construts Element动作,并将返回的element添加到Document对象。

    2.3.2 add方法
     /**
      * 添加信息
      * @param file
      * @param userInfo
      * @param sc
      */
     public void add(String file,Object facade,int builderType,ServletContext sc){
      doc = (Document)InputFactory.newJDOMInput().inputXML(file,sc);

      doc.getRootElement().addContent(BuilderFactory.getBuilder(builderType).addBuilder(true,facade));
      OutputFactory.newJDOMOutput().outputXML(file,doc);

      if (logger.isDebugEnabled()) {logger.debug("add() - 数据添加完毕");}
     }

    add方法跟create方法的唯一区别就是在Construts element之前,需要读取需要修改的内容。
    至于ServletContext sc这个形式参数,大家不用理会,这个是用来从ParserPool获得XMLParser对象用的,直接设置为null就可以了,不会影响实际操作。


    其他的几个方法我就不一一叙述了,实在大同小异。根据前面的分析,完全可以理解。详情请看源码吧。

    2.4 facade对象到底是什么?
    从我给出的类图可以看到UserInfoFacade类。(facade外观模式,详情请参考《Thinking in Patterns With Java》)它的作用实际是作为其他三个DTO的外界接口,用来简化与外界的操作。
    细心的朋友还可能看到一个ElementDecorator类。(decorator装饰模式,详情请参考《Thinking in Patterns With Java》)这个是用来在ConcreteBuilder类里装饰ChildElement到元组Element。
    当然如果你的XML文档并不复杂可能你根本不需要这样一个facade对象,这时你完全可以用简单的DTO来替代它。

    3.0 适用范围
    实际上想在这个基础上添加对其他XML文档,只需要基于Builder接口写出具体ConcreteBuilder类和facade类或者简单DTO就可以了。
    所以它几乎是适用于绝大部分XML文档的。
    另外input和output留出了接口,想换成DOM4J也不麻烦。
    测试文件是 org.jomper.test.XMLDAOTest
    我只是抛砖引玉,写这个文档的主要目的是希望能在大家的批评和意见下一起完善它,来简化所有XML爱好者编程。这是我的邮箱jomper.cn@gmail.com


    4.0 参考文献
    [1] Wes Biggs & Harry Evans,用 JDOM 简化 XML 编程. IBM Java Technology .
    [2] Jason Hunter,JDOM Makes XML Easy.
    [3] Bruce Eckle,Thinking in Patterns With Java. 电子工业出版社.
    [4] Brett McLaughlin,Java Enterprise Best Practices.O'Reilly.


    关键词:
    元组元素: 元组元素相当于关系数据库里元组的概念,以一个元素来对应数据库里的一行数据。
    DTO: Data Transform Object 数据传递对象。在《J2EE设计模式》(P139)已经建议用这个概念来替代VO(Value Object)。


    下面是很多懒得看文档的人们喜欢的。
    源码下载:


    [此贴子已经被作者于2006-3-24 8:08:19编辑过]
    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2006/3/23 22:45:00
     
     cong3232 帅哥哟,离线,有人找我吗?
      
      
      等级:大一新生
      文章:0
      积分:58
      门派:XML.ORG.CN
      注册:2005/2/23

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给cong3232发送一个短消息 把cong3232加入好友 查看cong3232的个人资料 搜索cong3232在『 DOM/SAX/XPath 』的所有贴子 引用回复这个贴子 回复这个贴子 查看cong3232的博客5
    发贴心情 
    楼主好像少了一个包的文件.在你提供的原代码中少了一个文件.
    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2006/5/11 10:12:00
     
     GoogleAdSense
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 DOM/SAX/XPath 』的所有贴子 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2024/5/8 22:20:43

    本主题贴数5,分页: [1]

    管理选项修改tag | 锁定 | 解锁 | 提升 | 删除 | 移动 | 固顶 | 总固顶 | 奖励 | 惩罚 | 发布公告
    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    85.938ms