文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

如何通过递归方法实现用json-diff渲染json字符串对比结果

2022-12-08 20:54

关注

前言

上一篇,对比了js-diff和json-diff,发现js-diff对比的结果返回的是拆分后字符串并且字符串中带有换行符跟空格,将拆分后的字符串拼接可以得到完整的两个json格式化后的信息。但是json-diff只返回了两个json中有修改的的部分,并且返回类型还要根据值类型来进行判断。

分析json-diff的结构

用两个数组嵌套对象,对象嵌套数组的比较复杂的json进行对比,获得的数据如下:

var json1 = {
  name: '小明',
  age: '22',
  hobby: ['篮球', '足球', '羽毛球'],
  grade: {
    English: ['130', '129', '135'],
    Chinese: ['120', '118', '122'],
    sports: ['90', '90', '90'],
  },
  honor: [{ desc: '获得数学竞赛第一名', info: [{ score: '100', ranking: 1 }, 2, 3] }],
}
var json2 = {
  name: '小红',
  age: '22',
  hobby: ['乒乓球', '羽毛球'],
  grade: {
    English: ['120', '129', '125'],
    Chinese: ['140', '139', '136'],
    sports: ['90', '90', '90'],
  },
  honor: [{ desc: '获得作文比赛第一名', info: [{ score: '99', rank: 2 }, 2, 3] }],
}
var jsonDiff = {
    "name": {
        "__old": "小明",
        "__new": "小红"
    },
    "hobby": [
        [
            "-",
            "篮球"
        ],
        [
            "-",
            "足球"
        ],
        [
            "+",
            "乒乓球"
        ],
        [
            " "
        ]
    ],
    "grade": {
        "English": [
            [
                "-",
                "130"
            ],
            [
                "+",
                "120"
            ],
            [
                " "
            ],
            [
                "-",
                "135"
            ],
            [
                "+",
                "125"
            ]
        ],
        "Chinese": [
            [
                "-",
                "120"
            ],
            [
                "-",
                "118"
            ],
            [
                "-",
                "122"
            ],
            [
                "+",
                "140"
            ],
            [
                "+",
                "139"
            ],
            [
                "+",
                "136"
            ]
        ]
    },
    "honor": [
        [
            "~",
            {
                "desc": {
                    "__old": "获得数学竞赛第一名",
                    "__new": "获得作文比赛第一名"
                },
                "info": [
                    [
                        "~",
                        {
                            "ranking__deleted": 1,
                            "rank__added": 2,
                            "score": {
                                "__old": "100",
                                "__new": "99"
                            }
                        }
                    ],
                    [
                        " "
                    ],
                    [
                        " "
                    ]
                ]
            }
        ]
    ]
};

可以观察到:

解析结构图如下:

太绕了,画图之后才看的明白一点ORZ...

用递归方法拼接json字符串

首先创建一个函数用来判断json是否为数组,renderobj(diffObj, originObj, n),diffObj表示当层的diff对象,originObj表示当层的json1对象,n表示深度,第一层深度为0,主要为了方便计算缩进。

renderobj函数:

// 定义remove和add队列
const removeList = [];
const addlist = [];
if (diffObj instanceof Array) {
    // 数组的判断
} else if (typeof diffObj == 'object'){
    if (diffObj.__new) {
        // 字符串修改
    } else {
        // 非数组对象修改
    }
}

字符串修改

当diffObj.__new为真时,__old同时有值,表示字符串做修改,此时可以直接把__new放到addList,__old存入removeList。

addlist.push(`<span style="color:red;">"${diffObj.__new}"</span>,<br/>`);
removeList.push(`<span style="color:red;">"${diffObj.__old}"</span>,<br/>`);

非数组对象修改

const { addHtml, removeHtml } = renderObject(diffObj, originObj, n);
addlist.push(addHtml);
removeList.push(removeHtml);

非数组对象要判断key的值,创建函数renderObject(diffObj, originObj, n),传参同renderobj。

const addlist = [];
const removeList = [];
addlist.push(`{</br>`);
removeList.push(`{</br>`);

// 遍历originObj,遍历diffObj...

addlist.push(`${spaceStr.repeat(n)}},</br>`);
removeList.push(`${spaceStr.repeat(n)}},</br>`);
return {
  addHtml: addlist.join(''),
  removeHtml: removeList.join(''),
};

为啥要分别遍历originObj和diffObj?因为json1对象中没有新增的key,diffObj中没有返回未修改key。

const spaceStr = '    ';
Object.keys(originObj).forEach(key => {
  const keyVal = diffObj[key];
  if (keyVal) {
   // renderobj重新判断修改类型
    const { addHtml, removeHtml } = renderobj(keyVal, originObj[key], n + 1);
    if (keyVal.__new) {
      // 当字符串修改时,将整行标红
      addlist.push('<div class="error-line-add">');
      removeList.push('<div class="error-line-remove">');
    }
    addlist.push(`${spaceStr.repeat(n + 1)}"${key}": ${addHtml}`);
    removeList.push(`${spaceStr.repeat(n + 1)}"${key}": ${removeHtml}`);
    if (keyVal.__new) {
      addlist.push(`</div>`);
      removeList.push(`</div>`);
    }
  } else {
    const remove = diffObj[key + '__deleted'];
    if (remove) {
      // 删除的属性
      removeList.push('<div class="error-line-remove">');
      removeList.push(
        `<span style="color:red;">${spaceStr.repeat(n + 1)}"${key}": ${renderJson(
          remove,
          n + 1
        )}</span></br>`
      );
      removeList.push('</div>');
    } else {
      // 没修改的属性直接存入
      addlist.push(
        `${spaceStr.repeat(n + 1)}"${key}": ${renderJson(originObj[key], n + 1)}</br>`
      );
      removeList.push(
        `${spaceStr.repeat(n + 1)}"${key}": ${renderJson(originObj[key], n + 1)}</br>`
      );
    }
  }
})
Object.keys(diffObj).forEach(key => {
  // 新增的属性,json1中没有,从diffObj中遍历
  if (key.includes('__added')) {
    addlist.push('<div class="error-line-add">');
    addlist.push(
      `<span style="color: red;">${spaceStr.repeat(n + 1)}"${key.replace('__added', '')}": "${diffObj[key]}",</br></span>`
    );
    addlist.push('</div>');
  }
});

数组对象修改

遍历diffObj,判断item[0]的值,当值为空格时,需要从json1中获取原属性值,diffObj中空格所在的索引位置有可能和originObj中索引的位置不同,要排除掉'+'新增的成员;当值为'+'时,直接将值存入addList;当值为'-'时,直接将值存入removeList;当值为'~'时,表示有修改,修改类型不确定需要重新循环判断。

addlist.push(`[</br>`);
removeList.push(`[</br>`);
diffObj.forEach((item, i) => {
    switch (item[0]) {
      case '~': {
        // 有修改,重新判断修改的值的类型
        const { addHtml, removeHtml } = renderobj(item[1], originObj[i], n + 1);
        addlist.push(`${spaceStr.repeat(n + 1)}${addHtml}`);
        removeList.push(`${spaceStr.repeat(n + 1)}${removeHtml}`);
        break;
      }
      case '-': {
        // 删除属性
        removeList.push('<div class="error-line-remove">');
        removeList.push(
          `<span style="color: red;">${spaceStr.repeat(n + 1)}${renderJson(
            item[1],
            n + 1
          )}</br>`
        );
        removeList.push('</div>');
        break;
      }
      case '+': {
        // 新增属性
        addlist.push('<div class="error-line-add">');
        addlist.push(
          `<span style="color: red;">${spaceStr.repeat(n + 1)}${renderJson(
            item[1],
            n + 1
          )}</br>`
        );
        addlist.push('</div>');
        break;
      }
      case ' ': {
        // 属性未修改,从originObj中获取,注意对应的index不包括新增的属性
        const index = diffObj.slice(0, i).filter(item => item[0] != '+').length;
        const value = originObj[index];
        const itemStr = `${spaceStr.repeat(n + 1)}${renderJson(value, n + 1)}</br>`;
        addlist.push(itemStr);
        removeList.push(itemStr);
        break;
      }
    }
});
addlist.push(`${spaceStr.repeat(n)}],</br>`);
removeList.push(`${spaceStr.repeat(n)}],</br>`);

renderJson函数,用来格式化json值:

const renderJson = (json, n) => {
  if (!json) {
    return "";
  }
  if (typeof json == "string" || typeof json == "number") {
    return `"${json}",`;
  }
  return `${JSON.stringify(json, null, "\t")
    .replace(new RegExp("\n", "g"), `</br>${spaceStr.repeat(n)}`)
    .replace(new RegExp("\t", "g"), spaceStr.repeat(n))},`;
};

最后对比显示结果如下:

总结

到此这篇关于如何通过递归方法实现用json-diff渲染json字符串对比结果的文章就介绍到这了,更多相关json-diff渲染json字符串对比结果内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-前端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯