我需要比较两个代表json对象的字符串。出于测试目的,我需要一种方法来比较这些字符串,而不仅忽略子元素顺序(这很常见),而忽略了jsons数组属性中元素的顺序。即:
group: {
id: 123,
users: [
{id: 234, name: John},
{id: 345, name: Mike}
]
}
应该等于:
group: {
id: 123,
users: [
{id: 345, name: Mike},
{id: 234, name: John}
]
}
理想情况下,我需要一些javascript lib,但也欢迎其他方法。
答案 0 :(得分:5)
他们有一个松散的断言。
松散:
JSONAssert.assertEquals(exp, act, false);
严格的:
JSONAssert.assertEquals(exp, act, true);
答案 1 :(得分:1)
您可以对数组进行切片,按Id对它们进行排序,然后将它们串化为JSON并比较字符串。对于很多成员来说,它应该非常快。如果您复制ID,它将失败,因为sort不会改变顺序。
答案 2 :(得分:0)
我不知道这样的事情是否存在,但你可以自己实现它。
var group1 = {
id: 123,
users: [
{id: 234, name: "John"},
{id: 345, name: "Mike"}
]
};
var group2 = {
id: 123,
users: [
{id: 345, name: "Mike"},
{id: 234, name: "John"}
]
};
function equal(a, b) {
if (typeof a !== typeof b) return false;
if (a.constructor !== b.constructor) return false;
if (a instanceof Array)
{
return arrayEqual(a, b);
}
if(typeof a === "object")
{
return objectEqual(a, b);
}
return a === b;
}
function objectEqual(a, b) {
for (var x in a)
{
if (a.hasOwnProperty(x))
{
if (!b.hasOwnProperty(x))
{
return false;
}
if (!equal(a[x], b[x]))
{
return false;
}
}
}
for (var x in b)
{
if (b.hasOwnProperty(x) && !a.hasOwnProperty(x))
{
return false;
}
}
return true;
}
function arrayEqual(a, b) {
if (a.length !== b.length)
{
return false;
}
var i = a.length;
while (i--)
{
var j = b.length;
var found = false;
while (!found && j--)
{
if (equal(a[i], b[j])) found = true;
}
if (!found)
{
return false;
}
}
return true;
}
alert(equal(group1, group2))
答案 3 :(得分:0)
以下是我对自定义实施的尝试:
var equal = (function(){
function isObject(o){
return o !== null && typeof o === 'object';
}
return function(o1, o2){
if(!isObject(o1) || !isObject(o2)) return o1 === o2;
var key, allKeys = {};
for(key in o1)
if(o1.hasOwnProperty(key))
allKeys[key] = key;
for(key in o2)
if(o2.hasOwnProperty(key))
allKeys[key] = key;
for(key in allKeys){
if(!equal(o1[key], o2[key])) return false;
}
return true;
}
})();
包含测试用例的示例:
var p1 = {
tags: ['one', 'two', 'three'],
name: 'Frank',
age: 24,
address: {
street: '111 E 222 W',
city: 'Provo',
state: 'Utah',
zip: '84604'
}
}
var p2 = {
name: 'Frank',
age: 24,
tags: ['one', 'two', 'three'],
address: {
street: '111 E 222 W',
city: 'Provo',
state: 'Utah',
zip: '84604'
}
}
var p3 = {
name: 'Amy',
age: 24,
tags: ['one', 'two', 'three'],
address: {
street: '111 E 222 W',
city: 'Provo',
state: 'Utah',
zip: '84604'
}
}
var p4 = {
name: 'Frank',
age: 24,
tags: ['one', 'two', 'three'],
address: {
street: '111 E 222 W',
city: 'Payson',
state: 'Utah',
zip: '84604'
}
}
var p5 = {
name: 'Frank',
age: 24,
tags: ['one', 'two'],
address: {
street: '111 E 222 W',
city: 'Provo',
state: 'Utah',
zip: '84604'
}
}
var equal = (function(){
function isObject(o){
return o !== null && typeof o === 'object';
}
return function(o1, o2){
if(!isObject(o1) || !isObject(o2)) return o1 === o2;
var key, allKeys = {};
for(key in o1)
if(o1.hasOwnProperty(key))
allKeys[key] = key;
for(key in o2)
if(o2.hasOwnProperty(key))
allKeys[key] = key;
for(key in allKeys){
if(!equal(o1[key], o2[key])) return false;
}
return true;
}
})();
var cases = [
{name: 'Compare with self', a: p1, b: p1, expected: true},
{name: 'Compare with identical', a: p1, b: p2, expected: true},
{name: 'Compare with different', a: p1, b: p3, expected: false},
{name: 'Compare with different (nested)', a: p1, b: p4, expected: false},
{name: 'Compare with different (nested array)', a: p1, b: p5, expected: false}
];
function runTests(tests){
var outEl = document.getElementById('out');
for(var i=0; i < tests.length; i++){
var actual = equal(tests[i].a, tests[i].b),
result = tests[i].expected == actual
? 'PASS'
: 'FAIL';
outEl.innerHTML +=
'<div class="test ' + result + '">' +
result + ' ' +
tests[i].name +
'</div>';
}
}
runTests(cases);
&#13;
body{
font-family:monospace;
}
.test{
margin:5px;
padding:5px;
}
.PASS{
background:#EFE;
border:solid 1px #32E132;
}
.FAIL{
background:#FEE;
border:solid 1px #FF3232;
}
&#13;
<div id=out></div>
&#13;
答案 4 :(得分:0)
我喜欢弗朗西斯的解决方案,并且效果很好。
只需在equal
函数的开头添加以下空检查,以防止输入为空或未定义的错误。
if (a == null && b == null) {
return true;
}
if (a == null || b == null) {
return false;
}
因此整个解决方案如下所示:
function equal(a, b) {
if (a == null && b == null) {
return true;
}
if (a == null || b == null) {
return false;
}
if (typeof a !== typeof b) return false;
if (a.constructor !== b.constructor) return false;
if (a instanceof Array)
{
return arrayEqual(a, b);
}
if(typeof a === "object")
{
return objectEqual(a, b);
}
return a === b;
}
function objectEqual(a, b) {
for (var x in a)
{
if (a.hasOwnProperty(x))
{
if (!b.hasOwnProperty(x))
{
return false;
}
if (!equal(a[x], b[x]))
{
return false;
}
}
}
for (var x in b)
{
if (b.hasOwnProperty(x) && !a.hasOwnProperty(x))
{
return false;
}
}
return true;
}
function arrayEqual(a, b) {
if (a.length !== b.length)
{
return false;
}
var i = a.length;
while (i--)
{
var j = b.length;
var found = false;
while (!found && j--)
{
if (equal(a[i], b[j])) found = true;
}
if (!found)
{
return false;
}
}
return true;
}
答案 5 :(得分:0)
此答案描述了使用 DeltaJSON REST API 解决问题的解决方案。 DeltaJSON 是一种商业产品,可将 API 作为服务 (SaaS) 或通过可在本地运行的 REST 服务器提供:
java -jar deltajson-rest-1.1.0.jar
arrayAlignment
属性设置为 orderless
。下面的示例代码显示了如何使用此属性设置调用 API:
async function runTest() {
const group1 = {
id: 123,
users: [
{ id: 234, name: "John" },
{ id: 345, name: "Mike" }
]
};
const group2 = {
id: 123,
users: [
{ id: 345, name: "Mikey" },
{ id: 234, name: "John" }
]
};
// call wrapper function that makes the REST API call:
const isEqual = await compare(group1, group2);
// log the comparison result: true
console.log("isEqual", isEqual);
}
async function compare(aData, bData) {
const aString = JSON.stringify(aData);
const bString = JSON.stringify(bData);
const blobOptions = { type: "application/json" };
var formdata = new FormData();
formdata.append("a", new Blob([aString], blobOptions));
formdata.append("b", new Blob([bString], blobOptions));
formdata.append("arrayAlignment", "orderless");
const myHeaders = new Headers();
myHeaders.append("Accept", "application/json");
var requestOptions = {
method: "POST",
headers: myHeaders,
body: formdata,
redirect: "follow"
};
try {
const response = await fetch(
"http://localhost:8080/api/json/v1/compare",
requestOptions
);
const jsonObj = await response.json();
console.log(jsonObj);
const dataSets = jsonObj.dx_deltaJSON.dx_data_sets;
const isEqual = dataSets === "A=B";
return isEqual;
} catch (e) {
console.error(e);
}
}
// run the test:
runTest(); // true
DeltaJSON Rest API 响应是 JSON 输入的注释形式。添加了额外的 dx_
前缀属性来描述更改。 JSON 中还包含元数据 dx_deltaJSON
属性。
dx_deltaJSON
属性的值是一个具有 dx_data_sets
属性的对象,我们可以测试该属性以查看(在双向比较中)该值为 A=B
。< /p>
这里的结果与问题中的输入略有不同。在这里,以及更改数组项的顺序,'Mike' 已更改为 'Mikey':
{
"dx_deltaJSON": {
"dx_data_sets": "A!=B",
"dx_deltaJSON_type": "diff",
"dx_deltaJSON_metadata": {
"operation": {
"type": "compare",
"input-format": "multi_part",
"output-format": "JSON"
},
"parameters": {
"dxConfig": [],
"arrayAlignment": "orderless",
"wordByWord": false
}
},
"dx_deltaJSON_delta": {
"id": 123,
"users": [
{
"id": 345,
"name": {
"dx_delta": {
"A": "Mike",
"B": "Mikey"
}
}
},
{
"id": 234,
"name": "John"
}
]
}
}
}