SharePoint中详细的版本对比

众所周知,在SharePoint 2007的时候,列表和文档库都支持了版本控制,并且在版本控制中,可以看到哪些字段发生了变化,如下图所示:

SharePoint中详细的版本对比_第1张图片

不过在最近,某个项目中,客户说:这个版本历史记录没啥用啊(做的是公文管理模块),我得知道我发的好长好长一段的公文(用的一个多行文本实现的),到底是什么地方变了,得用个红字给我标出来。然后我们乙方在场的人就无语了。

这种对比两个文本字符串区别的功能,有个正式的名字叫做“字符串编辑距离(Edit Distance)”,通俗一点说就是怎么从一个字符串,通过增加、变更、删除的动作,变成另一个字符串的。这是动态规划算法的一个典型应用,不过要自己来写(而且客户的这个发文还是html格式的),恐怕不是一朝一夕能搞得定的。

其实SharePoint中,这种详细的版本内容比较确实是有的,那就是在wiki页面库中,版本历史记录可以记录下两个不同版本的正文有什么区别,不过只支持wiki库的正文字段,效果是这个样子的:

SharePoint中详细的版本对比_第2张图片

通过跟踪源代码,发现其实在SharePoint中,这种版本对比功能已经在API中提供了接口,那就是SPDiffUtility(在Microsoft.SharePoint.Utilities命名空间中)的静态方法Diff。这个方法有三个参数,前两个参数是需要对比的两个字符串,第三个参数指定最多返回多少个差异的地方(一个int),方法返回字符串的差异结果,是一段html,样子就像是上面那张图的样子。

有了这个方法再实现起来就相对容易很多了,不过这个方法有如下两个大问题:

  1. 这个方法只支持对比html格式的字符串,对于纯文本字符串,在返回的时候,也是html格式,但是换行就无法以“换行”的形式显示出来了。
  2. 通过对这个方法进行反编译可以看到,这个方法在进行两个字符串对比的时候,是按照空格作为两个单词的分隔符(这个分隔算法是用一个整则表达式,\s+写死在代码里的),所以我们看到在中文的情况下,就会出现上图那样的状况,即使变动的只是一个字,但是系统也认为是整个段落的变动。
  3. 在SharePoint这个方法的实现中,只有“新增”和“删除”两种动作,变更的动作是通过“删除”+“新增”的方式来表示的,相对来说比较不直观。

 

第一个问题,其实解决起来很简单,把纯文本转换成html就行了,做一个HtmlEncode,然后把换行符替换为“<br/>”就行了。

第二个问题,其实说起来也很简单,在我们最终的实现方式中,是以“短句”为单位进行的对比,方法就是先对待比较的字符串进行一下处理,把几个句尾标点替换成包含空格的标记,比较完之后再替换回来:

   1: private string ChangeString(string str)
   2: {
   3:     if (str == null)
   4:        return "";
   5:     return str.Replace("。", "。`` ").Replace("!", "!`` ").Replace("?", "?`` ").Replace("、", "、`` ")
   6:         .Replace(",", ",`` ").Replace(":", ":`` ").Replace(";", ";`` ");
   7: }

比较完之后,删除里面所有的“`` ”就可以了(这个序列在正常的文本中基本上不会出现),这样再调用方法的时候,替换后的部分就包含空格,可以被SharePoint识别为对比的分隔符了。

至于第三个问题,基本上没有很好的办法,不过一般客户都能够接受。

重新仿照SharePoint的方式写了一个新的页面,传入待对比的列表的ID、条目的ID和字段的名称,修改之后的结果如下图:

SharePoint中详细的版本对比_第3张图片

可以看到,这要比之前的那个效果好很多了。

如果希望重新定义“已删除”和“已添加”的样式,也很容易,这是两个css(ms-diffdelete和ms-diffinsert),直接修改样式表就行了。

你可能感兴趣的:(SharePoint)