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

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

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 9576 个阅读者浏览上一篇主题  刷新本主题   平板显示贴子 浏览下一篇主题
     * 贴子主题: [原创]对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
     
     GoogleAdSense
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 DOM/SAX/XPath 』的所有贴子 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2024/4/19 19:44:23

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

     *树形目录 (最近20个回帖) 顶端 
    主题:  [原创]对XML文档操作的通用CRUD(JDOM版)(7223字) - jomper,2006年3月22日
        回复:  楼主好像少了一个包的文件.在你提供的原代码中少了一个文件.(60字) - cong3232,2006年5月11日
        回复:  [color=#FF0000]能不能让我 编辑一下原来的帖子,不然这样好郁闷.[/color]..(3100字) - jomper,2006年3月23日
        回复:  mark(4字) - malcolm,2006年3月23日
        回复:  嗯,不错,关注中。。。。。。(28字) - SATOKO2006,2006年3月23日

    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    62.500ms