我正在尝试创建一个函数来深入比较两个 JSON 对象(objectA 与 objectB)。然后生成一个唯一的 JSON 对象,它只有节点树到不同的数据值。
我的想法是将部分 JSON 传送到一个递归函数中,再加上一个保存数据路径的数组。但是当我按照编写的代码运行代码时,我的路径数组中出现了额外的元素。
理想情况下,最终结果将提供如下路径:
[ "level1c", "level2b", "level3c"]
但不幸的是我得到:
[“level1a”、“level1b”、“level1c”、“level2b”、“level3c”]
曾经,我有一个可靠的数据路径,然后我打算用它来构建一个新的 JSON 对象,该对象仅包含不同的节点。
function compareJSON( primary, secondary ){
function diffJSON( primary, secondary, path ){
var p = path.slice(); // copy array
var keys = Object.keys( secondary );
var sVal;
var pVal;
for( var i=0, x=keys.length; i<x; i++ ){
sVal = secondary[keys[i]];
pVal = primary[keys[i]];
if( sVal !== pVal ){
p.push( keys[i] );
if( typeof sVal === 'object' && !Array.isArray( sVal ) ){
diffJSON( pVal, sVal, p );
}else{
if( Array.isArray( sVal ) ){
compareArray( sVal, pVal, p );
}else{
updateResult( sVal, p );
}// END if( !Array.isArray() )
}// END if( typeof sVal === 'object' ... )
}// END if( sVal !== pVal )
}// END for loop
function compareArray( arr, arr2, path ){
// compare arrays
}
function updateResult( data, path ){
console.log( data, path );
}// END function updateResult()
}// END function diffJSON()
diffJSON( primary, secondary, [] );
}// END function compareJSON()
附加信息:
- 我知道 objectA 和 objectB 的结构相同;其中 objectB 永远只是对 objectA 中数据的修改。
- 寻找低于 ES6 的解决方案(旧浏览器支持很有趣)。
- 主要问题是我如何捕捉到不同数据的正确节点路径;欢迎任何有关如何改进核心代码的提示/技巧/评论,但不是真正的答案。
这是实践中的代码,它在控制台中打印出一个值,该值被发现在 json2(与 json1 相比)和关联的路径数组中不同:
'use strict';
function compareJSON( primary, secondary ){
function diffJSON( primary, secondary, path ){
var p = path.slice(); // copy array
var keys = Object.keys( secondary );
var sVal;
var pVal;
for( var i=0, x=keys.length; i<x; i++ ){
sVal = secondary[keys[i]];
pVal = primary[keys[i]];
if( sVal !== pVal ){
p.push( keys[i] );
if( typeof sVal === 'object' && !Array.isArray( sVal ) ){
diffJSON( pVal, sVal, p );
}else{
if( Array.isArray( sVal ) ){
compareArray( sVal, pVal, p );
}else{
updateResult( sVal, p );
}// END if( !Array.isArray() )
}// END if( typeof sVal === 'object' ... )
}// END if( sVal !== pVal )
}// END for loop
function compareArray( arr, arr2, path ){
var match = true;
for( var i=0, x=arr.length; i<x; i++ ){
if( arr[i] !== arr2[i] ){
match = false;
}
}
if( !match ){
updateResult( arr, path );
}
}
function updateResult( data, path ){
console.log( data, path );
}// END function updateResult()
}// END function diffJSON()
diffJSON( primary, secondary, [] );
}// END function compareJSON()
var json1 = {
level1a : {
level2a : {
level3a : 'apple',
level3b : ['happy', 'happy', 'joy', 'joy'],
level3c : {
level4a : 'sleep'
},
level3d : true
},
level2b : 'music',
level2c : {
level3a : 'future',
level3b : false,
level3c : ['bear', 'camel', 'elephant']
}
},
level1b : {
level2a : 'jeopardy',
level2b : 10200,
level2c : true,
level2d : {
level3a : 'aliens',
level3b : 'weekend'
}
},
level1c : {
level2a : 'fiber',
level2b : [1, 2, 4, 5, 6]
},
level1d : ['apple', 'cat', 'baby'],
level1e : true,
level1f : {
level2a : false,
level2b : true,
level2c : {
level3a : 'naruto',
level3b : 123,
level3c : 'test',
level3d : 'this',
level3e : 'thing'
},
level2d : true
}
};
var json2 = {
level1a : {
level2a : {
level3a : 'apple',
level3b : ['happy', 'happy', 'joy', 'joy'],
level3c : {
level4a : 'sleep'
},
level3d : true
},
level2b : 'music',
level2c : {
level3a : 'future',
level3b : false,
level3c : ['bear', 'camel', 'elephant', 'lion']
}
},
level1b : {
level2a : 'jeopardy',
level2b : 10200,
level2c : true,
level2d : {
level3a : 'ancient',
level3b : 'weekend'
}
},
level1c : {
level2a : 'fiber',
level2b : [1, 2, 4, 5, 6]
},
level1d : ['apple', 'cat', 'baby'],
level1e : true,
level1f : {
level2a : false,
level2b : true,
level2c : {
level3a : 'naruto',
level3b : 123,
level3c : 'spicy',
level3d : 'this',
level3e : 'thing'
},
level2d : true
}
};
compareJSON( json1, json2 );
感谢您的时间和支持:)
最佳答案
我对您的代码进行了一些修改,以拆分包含路径的变量和包含所有差异的数组。
我假设这两个结构是等价的,否则您需要对 a 和 b 的键进行交叉和比较,分别打印差异并在交叉处循环。
我正在使用 Object.prototype.toString 以便将来您可以添加更多案例(如果您想走那条路,可以友好地切换大小写)并减少检查.
//if you want you pass allDiffs and path here and enhance this function to print array positional diff also
var isEqualArrays = function compareArray( arr1, arr2 ){
if(arr1.length !== arr2.length) return false;
var match = true;
for( var i=0, x=arr1.length; i<x; i++ ){
if( arr1[i] !== arr2[i] ){
match = false;
}
}
return match;
}
var toString = Object.prototype.toString;
function compare (a, b, allDiffs, previousPath) {
var akeys = Object.keys(a);
for (key of akeys) {
var currentPath = previousPath.concat(key);
var typeOfa = toString.call(a[key]);
var typeOfb = toString.call(b[key]);
if(typeOfa !== typeOfb) {
allDiffs.push({path: currentPath, values: [a[key], b[key]] })
continue
}
if(typeOfa === '[object Array]') {
if(!isEqualArrays(a[key], b[key])){//remove this if , if you want enhance route
allDiffs.push({path: currentPath, values: [a[key], b[key]] })
}
continue;
}
if(typeOfa === '[object Object]') {
compare(a[key], b[key], allDiffs, currentPath)
continue
}
if(a[key] !== b[key]) {
allDiffs.push({path: currentPath, values: [a[key], b[key]] })
}
}
return allDiffs
}
var json1 = {
level1a : {
level2a : {
level3a : 'apple',
level3b : ['happy', 'happy', 'joy', 'joy'],
level3c : {
level4a : 'sleep'
},
level3d : true
},
level2b : 'music',
level2c : {
level3a : 'future',
level3b : false,
level3c : ['bear', 'camel', 'elephant']
}
},
level1b : {
level2a : 'jeopardy',
level2b : 10200,
level2c : true,
level2d : {
level3a : 'aliens',
level3b : 'weekend'
}
},
level1c : {
level2a : 'fiber',
level2b : [1, 2, 4, 5, 6]
},
level1d : ['apple', 'cat', 'baby'],
level1e : true,
level1f : {
level2a : false,
level2b : true,
level2c : {
level3a : 'naruto',
level3b : 123,
level3c : 'test',
level3d : 'this',
level3e : 'thing'
},
level2d : true
}
};
var json2 = {
level1a : {
level2a : {
level3a : 'apple',
level3b : ['happy', 'happy', 'joy', 'joy'],
level3c : {
level4a : 'sleep'
},
level3d : true
},
level2b : 'music',
level2c : {
level3a : 'future',
level3b : false,
level3c : ['bear', 'camel', 'elephant', 'lion']
}
},
level1b : {
level2a : 'jeopardy',
level2b : 10200,
level2c : true,
level2d : {
level3a : 'ancient',
level3b : 'weekend'
}
},
level1c : {
level2a : 'fiber',
level2b : [1, 2, 4, 5, 6]
},
level1d : ['apple', 'cat', 'baby'],
level1e : true,
level1f : {
level2a : false,
level2b : true,
level2c : {
level3a : 'naruto',
level3b : 123,
level3c : 'spicy',
level3d : 'this',
level3e : 'thing'
},
level2d : true
}
};
console.log(compare(json1, json2, [], []))
关于javascript - 生成差异 JSON,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52726613/