Adding deep search in JSON diff

the_7th_king
the_7th_king used Ask the Experts™
on
Hello,

This link provides an excellent JSON diff algorithm. : http://tlrobinson.net/projects/javascript-fun/jsondiff/
However, what it does not do is provide for deep search of element nodes.

Any idea how do we do this?

Thanks!
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Jon NormanInformation Systems Manager
Top Expert 2012

Commented:
do you have an example of where it is not working?

it seems to be coded to go down each node until it gets to the end.

Author

Commented:
JSON1:

[
   {
      "id":"210",
        "fees":"5000",
        "annualpayment":"9000",
        "memberlist":
      [
         {
            "memberid":"210O42597",
            "chairmanflag":"on",
            "meeting":"75",
            "exception":"0"
         },
         {
            "memberid":"210O80245",
            "chairmanflag":"on",
            "meeting":"75",
            "exception":"0"
         },
         {
            "memberid":"210O106573",
            "chairmanflag":"on",
            "meeting":"75",
            "exception":"0"
         }
      ]
   }
]


JSON2:

[
   {
      "id":"210",
        "fees":"5000",
        "annualpayment":"9000",
        "memberlist":
      [
         {
            "memberid":"210O106573",
            "chairmanflag":"on",
            "meeting":"75",
            "exception":"0"
         },
         {
            "memberid":"210O42597",
            "chairmanflag":"on",
            "meeting":"75",
            "exception":"0"
         },
         {
            "memberid":"210O80245",
            "chairmanflag":"on",
            "meeting":"75",
            "exception":"0"
         }
      ]
   }
]


The above 2 should compute as equal... which they do not as it compares the first node of first json with the first node of the second json... even though it should look through all the nodes.
Information Systems Manager
Top Expert 2012
Commented:
Ahhh I sort of see your point.

But an array is not equal if the elements are swapped around. For example an array might be used to store people's placing in a race or to say which functions to perform on something. If the results are messed up or the functions are not run in the order that they were supposed to the all sorts of problems could happen.

you will see that these two json objects are the same:

[
   {
      "id":"210",
        "fees":"5000",
        "annualpayment":"9000",
        "memberlist":
      {
         "210O42597":{
            "memberid":"210O42597",
            "chairmanflag":"on",
            "meeting":"75",
            "exception":"0"
         },
         "210O80245":{
            "memberid":"210O80245",
            "chairmanflag":"on",
            "meeting":"75",
            "exception":"0"
         },
         "210O106573":{
            "memberid":"210O106573",
            "chairmanflag":"on",
            "meeting":"75",
            "exception":"0"
         }
      }
   }
]

Open in new window

[
   {
      "id":"210",
        "fees":"5000",
        "annualpayment":"9000",
        "memberlist":
      {
         "210O106573":{
            "memberid":"210O106573",
            "chairmanflag":"on",
            "meeting":"75",
            "exception":"0"
         },
         "210O42597":{
            "memberid":"210O42597",
            "chairmanflag":"on",
            "meeting":"75",
            "exception":"0"
         },
         "210O80245":{
            "memberid":"210O80245",
            "chairmanflag":"on",
            "meeting":"75",
            "exception":"0"
         }
      }
   }
]

Open in new window



As for actually allowing arrays in any order then you would need to add some sort of testOnly variable to the compareTree function, then halfway down this routine if a is an array and b is also an array and they have the same amount of elements (length) then check each member of a against each member of b, but pass the check only through, then when you find a match call compareTree against the matching element in b. The problem I could see here is that you might have two elements in the array which are the same as each other.

This all depends on how far you actually want to go down this route, or do you just change your json to be an object?
Success in ‘20 With a Profitable Pricing Strategy

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden using our free interactive tool and use it to determine the right price for your IT services. Start calculating Now!

Author

Commented:
Very interesting explanation, JonNorman

I understand what that you're saying that it's pretty complicated to do the treecompare on the JSON itself and doing it after converting to objects might be simpler.

Can you elaborate on how would I do this kind of comparision if I converted the JSON strings to objects?

Many thanks!
Jon NormanInformation Systems Manager
Top Expert 2012
Commented:
Hi,

I guess that you just want to compare everything in it and return true for equal, and false for not equal, Taking Tom Robinson's code and modifying it I get this:

function compareJSON(a, b) {
    var typeA = typeofReal(a);
    var typeB = typeofReal(b);
    var aString = (typeA === "object" || typeA === "array") ? "" : String(a) + " ";
    var bString = (typeB === "object" || typeB === "array") ? "" : String(b) + " ";
    if (typeA!==typeB){
        return false;
    }else if (a === undefined && b=== undefined){
        return true;
    }else if (a === undefined) {
        return false;
    }else if (b === undefined) {
        return false;
    }else if (typeA !== typeB || (typeA !== "object" && typeA !== "array" && a !== b)) {
        return false;
    }
    if (typeA==="object"){
        var count = 0;
        for (var i in a) {
            count++;
            if (compareJSON(a[i], b[i])===false){
                return false;
            }
        }
        for (var i in b) {
            count--;
        }
        if (count!==0){
            return false;
        }
    }
    if (typeA==="array"){
        if (a.length!==b.length){
            return false;
        }
        for (var i = 0; i < a.length; i++) {
            if (compareJSON(a[i], b[i])===false){
                return false;
            }
        }
    }
    return true;
}
function isArray(value) {
    return value && typeof value === "object" && value.constructor === Array;
}
function typeofReal(value) {
    return isArray(value) ? "array" : typeof value;
}

/*above is needed, below is testing */

var SeventhKingJSON1 = [
   {
      "id":"210",
        "fees":"5000",
        "annualpayment":"9000",
        "memberlist":
      [
         {
            "memberid":"210O42597",
            "chairmanflag":"on",
            "meeting":"75",
            "exception":"0"
         },
         {
            "memberid":"210O80245",
            "chairmanflag":"on",
            "meeting":"75",
            "exception":"0"
         },
         {
            "memberid":"210O106573",
            "chairmanflag":"on",
            "meeting":"75",
            "exception":"0"
         }
      ]
   }
]
var SeventhKingJSON2 = [
   {
      "id":"210",
        "fees":"5000",
        "annualpayment":"9000",
        "memberlist":
      [
         {
            "memberid":"210O106573",
            "chairmanflag":"on",
            "meeting":"75",
            "exception":"0"
         },
         {
            "memberid":"210O42597",
            "chairmanflag":"on",
            "meeting":"75",
            "exception":"0"
         },
         {
            "memberid":"210O80245",
            "chairmanflag":"on",
            "meeting":"75",
            "exception":"0"
         }
      ]
   }
]
alert("7th_King_JSON_Compare: " + compareJSON(SeventhKingJSON1,SeventhKingJSON2))
var JonNormanJSON1 = [
   {
      "id":"210",
        "fees":"5000",
        "annualpayment":"9000",
        "memberlist":
      {
         "210O42597":{
            "memberid":"210O42597",
            "chairmanflag":"on",
            "meeting":"75",
            "exception":"0"
         },
         "210O80245":{
            "memberid":"210O80245",
            "chairmanflag":"on",
            "meeting":"75",
            "exception":"0"
         },
         "210O106573":{
            "memberid":"210O106573",
            "chairmanflag":"on",
            "meeting":"75",
            "exception":"0"
         }
      }
   }
]
var JonNormanJSON2 = [
   {
      "id":"210",
        "fees":"5000",
        "annualpayment":"9000",
        "memberlist":
      {
         "210O106573":{
            "memberid":"210O106573",
            "chairmanflag":"on",
            "meeting":"75",
            "exception":"0"
         },
         "210O42597":{
            "memberid":"210O42597",
            "chairmanflag":"on",
            "meeting":"75",
            "exception":"0"
         },
         "210O80245":{
            "memberid":"210O80245",
            "chairmanflag":"on",
            "meeting":"75",
            "exception":"0"
         }
      }
   }
]
alert("Jon_Norman_JSON_Compare: " + compareJSON(JonNormanJSON1,JonNormanJSON2))

Open in new window


Here is page where you can test it:
http://jsfiddle.net/nwkb5/

Author

Commented:
doing it with using objects seems like the best way to me
thanks for the GREAT help!

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial