JSON comparison

Hi,

I want to compare two JSON payloads in apigee

so how can I compare and check they both are same or not without using javascript

Any help would be appreciated

0 1 845
1 REPLY 1

how can I compare and check they both are same or not without using javascript

You cannot.

If you just want to compare JSON payloads, you can do a string comparison, using a conditional.

I suppose it would be something like

<Condition>string1 = string2</Condition>

But I'm certain that's not what you want to do. I think you want to evaluate semantic equivalence : does json #1 have the same properties as json #2, and with the same values? A straight string comparison will fail equivalence test with a difference in whitespace. Consider:

var jsonString1 = '{ "a" : 1234 }',
    jsonString2 = '{"a":1234}';

These two json strings are semantically equivalent, but the string comparison will return false.

Checking that json #1 has the same properties as json #2, and the same values on those properties, sounds simple enough, but it is not straightforward, and it does require some recursion (as json nests indefinitely) and as a result you need a 4GL like JS or Java in order to do the work.

You might be tempted to take the clever shortcut of relying on the fact that JSON.stringify() will normalize whitespaces. So you could Parse and then re-stringify the json, and compare THOSE strings.

var obj1 = JSON.parse(jsonString1), 
    obj2 = JSON.parse(jsonString2);
context.setVariable('json_equal', JSON.stringify(obj1) == JSON.stringify(obj2));

This works in the simple case, in which the properties are ordered the same way in each string. But AFAIK JSON.stringify() is not defined to sort the properties in any particular order, and it is not guaranteed to sort the properties in the same order each time! As a result, this comparison will fail with strings like this:

var jsonString1 = '{ "b": true, "a" : 1234 }',
    jsonString2 = '{"a":1234, "b" : true}';

JSON.stringify() normalizes the whitespace, but you need to normalize the json objects in a way that stably sorts the object properties. It gets a little more subtle with array values. With a json object in which the property names are differently ordered, we can agree that the objects are equivalent. But the agreement is not obvious when the values are arrays with differently ordered items. Is [3,2,1] equivalent to [1,2,3] ? In some cases you may want that, in some cases you may not want those two arrays to be treated as equivalent.

I found some hints on stackoverflow. In my tests, the following code works to handle sorting of object properties for purposes of testing equivalence.

  function normalizeObjOrArray(value) {
    return (typeof value === 'object') ?
      (Array.isArray(value) ?
       value.map(normalizeObjOrArray).sort() : // sorts array values
       Object.keys(value).sort().reduce(
         (o, key) => {
           const v = value[key];
           o[key] = normalizeObjOrArray(v);
           return o;
         }, {})
      ) :
    value;
  }
var obj1 = normalizeObjOrArray(JSON.parse(jsonString1)),
    obj2 = normalizeObjOrArray(JSON.parse(jsonString2));
var result = (JSON.stringify(obj1) === JSON.stringify(obj2));
context.setVariable('json_equal', result);