在上面的两篇文章之中,第一篇讲解了SFData所需要的数据结构,而在第二篇文章之中,介绍了如何为SFData提供这种数据(数据适配器),在这篇文章,我们将介绍系统集成的两个数据适配器SFDataXml和SFDataProject。
    这两个数据适配器都是基于XML格式的,虽然SFData根本不关心数据是不是来源于XML,但是我们也很难找到比xml更好的传递数据的方法,每个XML的数据适配器需要完成以下内容:
    1.将SFData需要的每一个元素和XML之中的节点对应起来,在请求特定的实体的时候,找到这个实体的数据在XML之中的节点位置;
    2.将XML文件之中的字符串转化为实体需要的属性格式
    基于这两点,我们有了两个数据适配器SFDataXml和SFDataProject,这两个数据适配器在第二点上基本上是相同的,也就是说,每一个实 体(例如任务),从XML之中读写其属性的方式基本上是类似的,两个适配器主要的不同在于文档主体结构的不同,不同点大致如下:
    1.SFDataProject主要是为了能直接支持从Microsoft Project里面导出的XML格式而提供的,而SFDataXml是在这个格式基础上的改进,改进的部分主要是考虑到分块加载和网络应用的性能;
    2.SFDataProject之中,任务都是在根文档的Tasks节点下,通过OutlineNumber属性来确定相互之间的树形从属关系,而在 SFDataXml之中,跟文档只有一个Task节点,而每个节点的字节点都应该在其父节点之下,这样就可以很容易的实现分块按需加载;
    3.考虑到资源甘特图的使用,SFDataXml之中的资源也是采用和上面说的任务一样的树形结构编排,而SFDataProject之中因为 Microsoft Project没有支持资源甘特图,资源仅仅是一个列表,这意味着SFDataProject将不能很好的支持资源甘特图的显示。
    4.SFDataXml支持ChildrenDataUrl和NextSiblingDataUrl这两个属性进行分块加载;
    5.SFDataProject实际上并没有支持所有的适配器接口,因为太多复杂,容易造成混乱,没有支持将moveTask和 moveResource接口,这意味着当用户存在移动操作的后,通过adapter.getXml()方法获取到的文档未必是正确的格式,而 SFDataXml没有这个问题,当然,在分块加载的模式下,SFDataXml的getXml()方法返回的文档仅仅包含已经下载的内容。
    以上是这两种适配器的主要不同,而这两个适配器在使用之中,都会遇到将XML节点之中的文本内容解析成为SFData指定的实体属性格式的问题(关于 SFData支持的属性列表,在第一篇文章里面可以找到),因此,在适配器之中,都存在一个实体的属性列表(当然,这两个列表实际上是相同的),我们可以 先看看这个列表:
实体类型 属性名称 XML节点名称 读写方法
任务 UID UID String
任务 Summary Summary Bool2Int
任务 ID ID Int
任务 OutlineNumber OutlineNumber String
任务 OutlineLevel OutlineLevel Int
任务 Start Start Time
任务 Finish Finish Time
任务 Name Name String
任务 ReadOnly ReadOnly Bool2Int
任务 PercentComplete PercentComplete Int
任务 Notes Notes String
任务 ConstraintType ConstraintType Int
任务 ConstraintDate ConstraintDate Time
任务 ActualStart ActualStart Time
任务 ActualFinish ActualFinish Time
任务 Hyperlink Hyperlink String
任务 HyperlinkAddress HyperlinkAddress String
任务 ClassName ClassName String
任务 Collapse Collapse Bool2Int
任务 LineHeight LineHeight Int
任务 Critical Critical Bool2Int
任务 BaselineStart BaselineStart Time
任务 BaselineFinish BaselineFinish Time
资源 UID UID String
资源 Summary Summary Bool2Int
资源 Collapse Collapse Bool2Int
资源 Name Name String
资源 ID ID Int
资源 OutlineNumber OutlineNumber String
资源 OutlineLevel OutlineLevel Int
资源 ReadOnly ReadOnly Bool2Int
资源 Notes Notes String
链接 UID UID String
链接 PredecessorUID PredecessorUID String
链接 SuccessorUID SuccessorUID String
链接 Type Type Int
资源分配 UID UID String
资源分配 TaskUID TaskUID String
资源分配 ResourceUID ResourceUID String
资源分配 Units Units Float

    从上表可以知道以下几点:
    1.目前支持的所有属性,系统默认读取的XML节点名称和属性名称都是保持一致的,例如任务有一个属性叫Start,则要求这个属性的内容在XML文件之中的节点名称也叫Start;
    2.目前SFDataXml和SFDataProject支持了前面提到的SFData的所有的属性,这意味着大部分情况下,不需要为这两个适配器添加新的属性支持
    3.每一种属性的读写方式必须和SFData之中指定的类型对应,例如"Start"属性,在SFData之中定义为“日期时间”类型的属性,这里的读写类型就只能是"Time"
    当然,假如要添加属性支持也是很容易的,只需要调用适配器的addTaskProperty(proName,tagName,type) , addResourceProperty(proName,tagName,type) , addLinkProperty(proName,tagName,type) , addAssignmentProperty(proName,tagName,type)这四个方法就可以为特定类型的实体添加新的属性支持,例如,我 们要增加任务的“创建时间”属性的支持,这当然是一个日期时间类型的属性,我们假设它在xml之中的节点名称为"CreateDate",我们可以这样添 加此属性:
    adapter.addTaskProperty("CreateDate","CreateDate",SFDataRender.getType("Time"));
    上面的第一个参数是属性名称,第二个参数是XML的节点名称(很多时候这两个参数是一致的,不过例如你的XML文件之中"StartTime"代表开始 时间而不是系统默认的"Start",就会不同了),第三个参数是XML内容读写类型,这个参数确定在读取实体的时候XML文件之中的字符串怎样转化成为 属性的值,也确定在更新实体的时候怎样将实体的属性怎样写入到XML文件之中,目前系统支持如下5种读写类型:
读写类型名称 说明
Int 读取XML时将XML节点内容使用parseInt(str)转化为整数,写入XML时将也保证必须写入整数字符串
Float 读取XML时将XML节点内容使用parseFloat(str)转化为浮点数,写入XML时将也保证写入浮点数字符串
String 不进行任何转化
Time 读取XML时将XML节点内容使用SFGlobal.getDate(str)转化为日期对象,写入XML时将日期属性使用SFGlobal.getDateString(value,"s")转化成2009-05-03T14:21:09的格式写入XML
Bool2Int 读取XML的时候将"1"转化为true,"0"转化为false,写入XML的时候相反

    虽然支持的读写方式比较少,可是实际上已经能够满足需求,毕竟,在这个转化的过程之中,不太可能去实现太复杂的逻辑,不过,如果实在需要自定义读写类 型,也是可以的,只需要定义readFunc和writeFunc即可,其中readFunc(node)的参数是一个XML节点,需要返回从该XML节 点读到的值,writeFunc(node,value)有两个参数,XML节点和属性值,需要将该属性写入到XML节点之中,例如,我们假设要实现一个 这样的读写方式: xml文件之中存储的是字符串"true"和"false",要求,而这个属性(例如Collapse)是一个布尔值,我们可以这么用:
    function readFunc(node)
    {
        if(SFAjax.getNodeValue(node)=="true"){return true;}
        return false;
    }
    function writeFunc(node,value)
    {
        var str=value?"true":"false";
        SFAjax.setNodeValue(node,str);
    }
    renderType=new SFDataRender(readFunc,writeFunc)
    adapter.addTaskProperty("Collapse","Collapse",renderType);
    这样,Collapse属性就改成了支持用字符串"true"和"false"来保存,而不是Project之中支持的"0"和"1"了。
    这篇文章之中,我们简单的讲解了SFDataXml和SFDataProject的实现,主要花精力说明了用户关心的属性自定义的问题,在这里有一点需 要补充:就是SFDataXml和SFDataProject都支持通过saveChange参数来指定是不是接收SFData的更改通知,如果 saveChange参数为true,你可以随时通过适配器的getXml()返回获得更改后的XML文件,如果为false,适配器则不会将用户的更改 保存下来,因为SFDataProject并没有完美的支持将用户的更改保存到文件,因此默认情况下,SFDataProject的saveChange 参数为false,而SFDataXml的saveChange参数为true.
    
posted on 2009-05-09 21:58  运筹帷幄  阅读(593)  评论(0编辑  收藏  举报