jsondiffpatch介绍

一、jsondiffpatch介绍

jsondiffpatch项目是一个将两个json文档、文本、数组...进行对比,并生成diff、patch信息的javascript库,该库支持多种formatter格式输出,以及提供可视化界面。

1、特点:

  • 支持浏览器、服务端(nodejs)使用;
  • 使用google-diff-match-patch 算法对长文本进行diff;
  • 对于数组的diff,使用LCS进行智能比较;说明:要匹配数组中的对象,必须提供objectHash函数(这是对象匹配的方式,否则将使用按位置的哑匹配)。有关更多详细信息,请参见数组差异文档
  • 支持多个格式:simple、json、delta(可翻译成增量信息,是jsondiffpatch定义的一种格式,见下面解释);
  • 支持unpatch(使用delta将对象恢复为其原始状态);
  • 多种输出格式(output formatters):
    • html
    • JSON Patch format RFC 6902 support
    • annotated json ,即:带有注释的json(html)
    • console (colored), try running ./node_modules/.bin/jsondiffpatch left.json right.json
    • 其他:Formatters documentation

2、支持的平台:

二、delta说明

delta用于表示增量的JSON格式(即jsondiffpatch.diff的输出),delta这种格式考虑到了可读性和低占用空间之间的平衡

了解这种格式的一种好方法是在Live Demo中使用“带注释的JSON”选项,并尝试不同的左/右示例,或者编辑左/右JSON以查看带注释的增量更新作为您的类型。

看一些示例:

Add:

delta = [ newValue ]

a value was added, i.e. it was undefined and now has a value.

Modified:

delta = [ oldValue, newValue ]

Deleted:

delta = [ oldValue, 0, 0 ]

Object inner changers:

delta = {
  property1: [ newValue1 ], // obj[property1] = newValue1
  property2: [ oldValue2, newValue2 ], // obj[property2] = newValue2 (and previous value was oldValue2)
  property5: [ oldValue5, 0, 0 ] // delete obj[property5] (and previous value was oldValue5)
}

Array with inner changes:

delta = {
  _t: 'a',
  index1: innerDelta1,
  index2: innerDelta2,
  index5: innerDelta5
}

Text Diffs:

delta = [ "some text", "some text modified" ]

text diff采用的是google diff-match-patch算法,如果字符串很长,可以设置minLength。

参考:https://github.com/benjamine/jsondiffpatch/blob/master/docs/deltas.md

三、Formatters说明

formatters是一个格式化的程序,可以将delta转换成其他格式。

1、html:

var delta = jsondiffpatch.diff(left, right);
// left is optional, if specified unchanged values will be visible too
document.getElementBy('the-diff').innerHTML = jsondiffpatch.formatters.html.format(delta, left);


// Also you can dinamically show/hide unchanged values
jsondiffpatch.formatters.html.showUnchanged();
jsondiffpatch.formatters.html.hideUnchanged();
// these will also adjust array move arrows (SVG), which is useful if something alters the html layout

说明:需要将 build/formatters.js 和 src/formatters/html.css 引入到页面中。

2、Annotated JSON:

这将以html形式呈现原始JSON delta,并带有注释,以解释每个部分的含义。这试图使JSON delta格式变得自解释。

var delta = jsondiffpatch.diff(left, right);
document.getElementBy('the-diff').innerHTML = jsondiffpatch.formatters.annotated.format(delta);

说明:需要将build/formatters.js 和 src/formatters/annotated.css 引入到页面中。

3、Console:

通过Node.js环境,在命令行上通过如下命令使用,以带有颜色的输出。

或者在程序中使用:

var delta = jsondiffpatch.diff(left, right);
var output = jsondiffpatch.formatters.console.format(delta);
console.log(delta);

// or simply
jsondiffpatch.console.log(delta);

4、JSON PATCH (RFC 6902)

var delta = jsondiffpatch.diff(left, right);
var output = jsondiffpatch.formatters.jsonpatch.format(delta);
console.log(delta);

输出采用标准的Json patch格式信息。注:textDiff 不支持JSON Patch。

参考:https://github.com/benjamine/jsondiffpatch/blob/master/docs/formatters.md

四、使用

1、安装:

//1.npm安装
npm install jsondiffpatch

var jsondiffpatch = require('jsondiffpatch').create(options);

//2.browser
引入/dist下的jsondiffpatch.umd.js

2、options:

var jsondiffpatch = require('jsondiffpatch').create({
    // used to match objects when diffing arrays, by default only === operator is used
    objectHash: function(obj) {
        // this function is used only to when objects are not equal by ref
        return obj._id || obj.id;
    },
    arrays: {
        // default true, detect items moved inside the array (otherwise they will be registered as remove+add)
        detectMove: true,
        // default false, the value of items moved is not included in deltas
        includeValueOnMove: false
    },
    textDiff: {
        // default 60, minimum string length (left and right sides) to use text diff algorythm: google-diff-match-patch
        minLength: 60
    },
    propertyFilter: function(name, context) {
      /*
       this optional function can be specified to ignore object properties (eg. volatile data)
        name: property name, present in either context.left or context.right objects
        context: the diff context (has context.left and context.right objects)
      */
      return name.slice(0, 1) !== '$';
    },
    cloneDiffValues: false /* default false. if true, values in the obtained delta will be cloned
      (using jsondiffpatch.clone by default), to ensure delta keeps no references to left or right objects. this becomes useful if you're diffing and patching the same objects multiple times without serializing deltas.
      instead of true, a function can be specified here to provide a custom clone(value)
      */
});

3、示例:

在github上下载release包:https://github.com/benjamine/jsondiffpatch/releases

编写测试的html文件,如下:

<!DOCTYPE html>
<html>
    <head>
        <script type='text/javascript' src="https://cdn.jsdelivr.net/npm/jsondiffpatch/dist/jsondiffpatch.umd.min.js"></script>
        <link rel="stylesheet" href="./html.css" type="text/css" />
        <link rel="stylesheet" href="./annotated.css" type="text/css" />
    </head>
    <body>
        <div id="visual"></div>
        <hr/>
        <div id="annotated"></div>
        <hr/>
        <div id="jsonPatch"></div>
        <script>
            var left = { a: 3, b: 4 };
            var right = { a: 5, c: 9 };
            var delta = jsondiffpatch.diff(left, right);

            // beautiful html diff
            document.getElementById('visual').innerHTML = jsondiffpatch.formatters.html.format(delta, left);

            // self-explained json
            document.getElementById('annotated').innerHTML = jsondiffpatch.formatters.annotated.format(delta, left);
            
            //JSON Patch 测试失败
            document.getElementById('jsonPatch').innerHTML = jsondiffpatch.formatters.jsonpatch.format(JSON.stringify(delta,null,"\t"));
        </script>
    </body>
</html>

将下载的release包解压后,在jsondiffpatch-0.3.11\docs\formatters-styles下可以找到css文件,效果如下:

注:按照官方文档示例,转成JSON Patch格式输出一直报错。

4、自带示例:

在release包中,jsondiffpatch-0.3.11\docs\demo中的示例,就是在线演示的界面。其中demo.js中有完整的使用方式。

/* global jsondiffpatch */
const instance = jsondiffpatch.create({
    objectHash: function(obj, index) {
    if (typeof obj._id !== 'undefined') {
        return obj._id;
    }
    if (typeof obj.id !== 'undefined') {
        return obj.id;
    }
    if (typeof obj.name !== 'undefined') {
        return obj.name;
    }
    return '$$index:' + index;
    },
});

function parseTxt(txt) {
    if (
        /^\d+(.\d+)?(e[+-]?\d+)?$/i.test(txt) ||
        /^(true|false)$/.test(txt) ||
        /^["].*["]$/.test(txt) ||
        /^[{[](.|\n)*[}\]]$/.test(txt)
    ) {
        return JSON.parse(txt, jsondiffpatch.dateReviver);
    }
    return txt; 
}

//使用
var left = parseTxt(json1);
var right = parseTxt(json2);

var delta = instance.diff(left, right);
if (typeof delta === 'undefined') {
    document.getElementById('visual').innerHTML = "<div style='margin:10px;font-size:30px;'>no diff...</div>";
} else {
    document.getElementById('visual').innerHTML = jsondiffpatch.formatters.html.format(delta, left);
    jsondiffpatch.formatters.html.hideUnchanged();
}

 

五、其他

1、google diff-match-patch算法:

1)该算法主要解决了对纯文本的:

github地址https://github.com/google/diff-match-patch 

2)支持的语言:

2、jsondiffpatch的plugin:

官网:https://github.com/benjamine/jsondiffpatch/blob/master/docs/plugins.md

diff(),patch()和reverse()函数是使用Pipes&Filters模式实现的,通过在管道上添加或替换过滤器,可以使其高度自定义。

3、jsondiffpatch的Array diff:

官网:https://github.com/benjamine/jsondiffpatch/blob/master/docs/arrays.md

数组diff是使用LCS实现的,LCS是文本差异工具使用的经典算法(此处使用数组项而不是文本行)。

1)object hash:

为了使LCS正常工作,它需要一种方法来匹配先前/原始(或左右)阵列之间的项目。在传统的文本差异工具中,这是微不足道的,因为需要逐字符比较两行文本。

默认情况下,使用===运算符,足以匹配所有JavaScript值类型(数字,字符串,布尔值)和对象引用(如果您将引用保持在左/右状态之间)。但是,如果找不到按引用或值匹配的项,则数组将回退到愚蠢的行为:按位置匹配项。

按位置匹配并不是最有效的选择(例如,如果在第一个位置添加了一个项目,则下面的所有项目都将被视为已修改),但是在大多数情况下,它都能产生预期的结果。只要移动/插入/删除仅在数组底部附近发生,就足够了。

这是因为如果2个对象的引用不相等(即同一对象),则这两个对象都被视为不同的值,因为在JavaScript中没有比较简单的解决方案可以比较两个任意对象。

为了利用LCS(和位置移动检测)的功能来改善结果,您需要提供一种比较2个对象的方法,即objectHash函数:

var delta = jsondiffpatch.create({
    objectHash: function(obj, index) {
      // try to find an id property, otherwise just use the index in the array
      return obj.name || obj.id || obj._id || '$$index:' + index;
    }
  }).diff({ name: 'tito' }, { name: 'tito' });

assert(delta === undefined); // no diff

2)moves:

作为对LCS的后验改进,检测到了从同一阵列内的位置移动的项目,因此进行了注册。这带来了一些好处:

  • 增量可能会小得多,因为不包括2次项的整个值(添加和删除)
  • 修补只会将项目移动到目标数组中,而不会删除和插入新实例。这样更有效,并且可以防止破坏对象图中的现有引用。
  • 如果move的项目是object或array,则diff在内部继续(嵌套diff)

默认情况下会检测到move,可以使用以下方法关闭移动检测:

var customDiffPatch = jsondiffpatch.create({
    arrays: {
      detectMove: false
    }
  };

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赶路人儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值