javascript - 生成差异 JSON

标签 javascript json diff

我正在尝试创建一个函数来深入比较两个 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/

相关文章:

javascript - angularjs 观察图像以查看其是否已完成加载

javascript - 将 Botium 脚本内存变量传递到断言器中

java - Grails:Linux 上的 JSON.parse() 错误 - 适用于 Windows - 难住了

git - 从命令行覆盖 .gitattributes

javascript - 如何根据 jquery datepicker 中的某些 datepicker 值禁用 future 日期

javascript - 客户端下载的图片格式

Java POJO 建模

jquery - 使用 Jquery $getJSON 如何动态为 Url 参数后的 [data] 参数创建数据?

intellij-idea - 使用 Intellij IDEA 13 在差异中启用显示行分隔符的差异

diff - mysqldbcompare可以提供sql补丁吗?