Languages
[Edit]
EN

JavaScript - json difference visualization

7 points
Created by:
Violetd
835

In this article, we're going to have a look at how to write own function to compare and visualise JSONs. This article is composed with in two parts: json difference checking and table visualzisation. 

Simple preview:

{"name": "John", "items": [ 1 , 2, "3", {"name": "Item 1", "z": [4]       }, 5         ]}
{"name": "John", "items": ["1", 2,  3 , {"name": "Item 2",          "x": 3},   "a", "b"]}
//                          u       u                       d    d   c       d  c    c
// Where: u - updated, c - created, d - deleted
JSONs difference visualisation with table in JavaScript
JSONs difference visualisation with table in JavaScript

Note: read this article to see console print version.

 

Custom solution

This section presents simple logic that visualise difference of jsons in table.

// ONLINE-RUNNER:browser;

<!doctype html>
<html>
  <style>

    table { border-collapse: collapse; font-size: 13px; }

    td { padding: 2px 4px; border: 1px solid; }

    td.label { width: 40px; }
    td.value { min-width: 50px; }

    td.unchanged { border-color: #dddada; background: #ffffff; }
    td.old { border-color: #ffa8a8; background: #ffd6d6; }
    td.new { border-color: #92ca92; background: #e5ffe5; }

    td table { width: 100% }

  </style>
  <script>

    // -------------------------------------------------------------------
    // difference calculator

    function getType(object) {
        return Object.prototype.toString.call(object);
    }

    function getDescription(type) {
        if (type == '[object Array]') {
            return 'array';
        }
        if (type == '[object Object]') {
            return 'object';
        }
        return 'simple';
    }

    function createOldItem(name, status, type, value) {
        return {
            name: name || null,
            status: status,
            oldType: getDescription(type),
            newType: null,
            oldValue: value,
            newValue: null,
        };
    }

    function createNewItem(name, status, type, value) {
        return {
            name: name || null,
            status: status,
            oldType: null,
            newType: getDescription(type),
            oldValue: null,
            newValue: value,
        };
    }

    var createDeletedItem = function(key, type, value) {
        return createOldItem(key, 'deleted', type, value);
    };

    var createCreatedItem = function(key, type, value) {
        return createNewItem(key, 'created', type, value);
    };

    function coverContent(entity, createItem) {
        var items = [ ];
        for (const key in entity) {
            if (entity.hasOwnProperty(key)) {
                items.push(coverEntity(key, entity[key], createItem));
            }
        }
        return items;
    }

    function coverEntity(name, entity, createItem) {
        var type = getType(entity);
        if (type === '[object Array]' || type === '[object Object]') {
            var content = coverContent(entity, createItem);
            return createItem(name, type, content);
        } else {
            return createItem(name, type, entity);
        }
    }

    function compareContent(a, b) {
        var items = [];
        for (const key in a) {
            if (a.hasOwnProperty(key)) {
                if (b.hasOwnProperty(key)) {
                    items.push(compareEntries(a[key], b[key], key));
                } else {
                    items.push(coverEntity(key, a[key], createDeletedItem));
                }
            }
        }
        for (const key in b) {
            if (b.hasOwnProperty(key)) {
              if(a.hasOwnProperty(key)){
                  continue;
              }
              items.push(coverEntity(key, b[key], createCreatedItem));
            }
        }
        return items;
    }

    function compareEntries(a, b, name) {
        var oldType = getType(a);
        var newType = getType(b);
        if (a === b) {
            return createOldItem(name, 'unchanged', oldType, a);
        }
        if (oldType == newType) {
            // both have array or object type:
            if (oldType === '[object Array]' || oldType === '[object Object]') {
                var oldValue = compareContent(a, b);
                return createOldItem(name, 'unchanged', oldType, oldValue);
            }
            // both have simple type: boolean, number, string, etc.:
            var description = getDescription(oldType);
            return {
                name: name || null,
                status: 'updated',
                oldType: description,
                newType: description,
                oldValue: a,
                newValue: b,
            };
        } else {
            // both have different types:
            var oldDescription = getDescription(oldType);
            var newDescription = getDescription(newType);
            return {
                name: name || null,
                status: 'updated',
                oldType: oldDescription,
                newType: newDescription,
                oldValue: (oldDescription == 'simple' ? a : coverContent(a, createDeletedItem)),
                newValue: (newDescription == 'simple' ? b : coverContent(b, createCreatedItem)),
            };
        }
    }

    // -------------------------------------------------------------------
    // difference visualization

    var rules = [
        {expression: /&/g, replacement: '&amp;' },  // keep this rule at first position
        {expression: /</g, replacement: '&lt;'  },
        {expression: />/g, replacement: '&gt;'  },
        {expression: /"/g, replacement: '&quot;'},
        {expression: /'/g, replacement: '&#039;'}
    ];

    function escapeValue(value) {
        if(value == null) {
            return null;
        }
        var result = String(value);
        for (var i = 0; i < rules.length; ++i) {
            var rule = rules[i];
            result = result.replace(rule.expression, rule.replacement);
        }
        return result;
    };

    function createRow(type, name, value) {
        var html = '<tr class="' + type + '">';
        if (name) {
            html += '  <td class="label ' + type + '">' + name + '</td>';
        }
        html += '  <td class="value ' + type + '">' + value + '</td>';
        html += '</tr>';
        return html;
    }

    function createNode(node) {
        var html = '';
        var name = escapeValue(node.name);
        if (node.oldType) {
            var oldValue = (node.oldType == 'simple' ? escapeValue(node.oldValue) : createTable(node.oldValue));
            if (node.status == 'unchanged') {
                return createRow('unchanged', name, oldValue);
            }
            html += createRow('old', name, oldValue);
        }
        if (node.newType) {
            var newValue = node.newType == 'simple' ? escapeValue(node.newValue) : createTable(node.newValue);
            html += createRow('new', name, newValue);
        }
        return html;
    }

    function createRows(nodes) {
        var html = '';
        for (var i = 0; i < nodes.length; ++i) {
            html += createNode(nodes[i]);
        }
        return html;
    }

    function createTable(nodes) {
        var html = '<table>' +
                   '  <tbody>' +
                        createRows(nodes) +
                   '  </tbody>' +
                   '</table>';
        return html;
    }

    function createReport(difference) {
        var html = '<table>' +
                   '  <tbody>' +
                        createNode(difference) +
                   '  </tbody>' +
                   '</table>';
        return html;
    }
    
    function showDifference(difference) {
        document.body.innerHTML = createReport(difference);
    }

  </script>
  <body>
    <script>

      function compareJsons(a, b) {
          var aObject = JSON.parse(a);
          var bObject = JSON.parse(b);
          var difference = compareEntries(aObject,  bObject);
          showDifference(difference);
      }

      var json1 = '{"name":"John","items":[1,2,"3",{"name":"Item 1","z":[4]},5]}';
      var json2 = '{"name":"John","items":["1",2,3,{"name":"Item 2","x":3},"a","b"]}';

      compareJsons(json1, json2);

    </script>
  </body>
</html>

 

See also

  1. JavaScript - write own compare JSONs function

  2. JavaScript - display object as expandable tree

Donate to Dirask
Our content is created by volunteers - like Wikipedia. If you think, the things we do are good, donate us. Thanks!
Join to our subscribers to be up to date with content, news and offers.

JavaScript - JSON

Native Advertising
🚀
Get your tech brand or product in front of software developers.
For more information Contact us
Dirask - we help you to
solve coding problems.
Ask question.

❤️💻 🙂

Join