BoxLang 🚀 A New JVM Dynamic Language Learn More...
An ColdFusion utility for checking if 2 JSON objects have differences
Important: JSON Objects NOT Serialized JSON Strings (Please de-serialize them first)
Apache License, Version 2.0.
Use CommandBox CLI to install:
box install jsondiff
property name="JSONDiff" inject="JSONDiff"; //wirebox
/* or (dot) folder path to the cfc */
JSONDiff = new path.to.the.cfc.JSONDiff(); //Instantiate Object
| Method | Purpose |
|---|---|
diff(first, second [, ignoreKeys, caseSensitive])
| List every change between two values |
diffByKey(first, second, uniqueKeys [, ignoreKeys, caseSensitive])
| Compare two arrays of structs by a unique key; returns
add / remove / update
|
isSame(first, second [, caseSensitive])
| true / false equality check |
summary(diffs)
| Count add, remove,
change, and update entries |
patch(original, diff)
| Apply a diff to the original and return the new value |
diffPatch(original, diff)
| Return the original with each value as {old, new, type}
|
displayDiff(original, diff)
| Return an HTML string visualising the changes |
visualizeDiff(first, second [, ignoreKeys, caseSensitive])
| Diff two values and return the HTML view |
Change type values are ADD,
REMOVE, CHANGE (and SAME in
diffPatch output).
Returns an array of changes. path is the location of the
change (struct keys and array positions, 1-based).
var original = { name: "Ann", tags: ["a", "b"], address: { city: "Rome" } };
var updated = { name: "Ann", tags: ["a", "c"], address: { city: "Paris", zip: "75001" } };
JSONDiff.diff(original, updated);
// Result
[
{ "type": "CHANGE", "path": ["tags", 2], "old": "b", "new": "c" },
{ "type": "CHANGE", "path": ["address", "city"], "old": "Rome", "new": "Paris" },
{ "type": "ADD", "path": ["address", "zip"], "old": "", "new": "75001" }
]
(Order of entries may vary.)
Keys in the ignore array are skipped during comparison.
JSONDiff.diff(
{ id: 1, updatedAt: "2024-01-01", status: "open" },
{ id: 1, updatedAt: "2024-02-01", status: "closed" },
["updatedAt"]
);
// Result: only status is reported
[ { "type": "CHANGE", "path": ["status"], "old": "open", "new": "closed" } ]
Comparisons are case-insensitive by default. Pass true
as the last argument to make them case-sensitive.
JSONDiff.diff({ name: "ann" }, { name: "ANN" }); // []
JSONDiff.diff({ name: "ann" }, { name: "ANN" }, [], true); // one CHANGE
Compares two arrays of structs by identifying rows with a unique key (a string, or an array for composite keys). Great for comparing database results.
JSONDiff.diffByKey(
[
{'id':26,'x':480,'y':0},
{'id':28,'x':482,'y':10},
{'id':32,'x':480,'y':12}
],
[
{'id':25,'x':10,'y':0},
{'id':65,'x':298,'y':0},
{'id':32,'x':415,'y':2}
],
'id'
);
// Result
{
"remove": [ // in the first array only
{ "key": 26, "data": { "id": 26, "x": 480, "y": 0 } },
{ "key": 28, "data": { "id": 28, "x": 482, "y": 10 } }
],
"add": [ // in the second array only
{ "key": 25, "data": { "id": 25, "x": 10, "y": 0 } },
{ "key": 65, "data": { "id": 65, "x": 298, "y": 0 } }
],
"update": [ // in both, with differences
{
"key": 32,
"orig": { "id": 32, "x": 480, "y": 12 },
"data": { "id": 32, "x": 415, "y": 2 },
"changes": [
{ "key": "x", "path": ["x"], "old": 480, "new": 415 },
{ "key": "y", "path": ["y"], "old": 12, "new": 2 }
]
}
]
}
Pass an array of column names. The returned key is an
array of the values (a single key returns a plain value).
JSONDiff.diffByKey(rowsA, rowsB, ["oid", "member_id"]);
// e.g. "key": [48280, 1988]
JSONDiff.isSame({ a: [1, { b: true }] }, { a: [1, { b: false }] }); // false
JSONDiff.isSame({ a: 1 }, { a: 1 }); // true
JSONDiff.isSame("Foo", "foo"); // true
JSONDiff.isSame("Foo", "foo", true); // false (case sensitive)
Applies a diff to the original and returns the resulting value. The inputs are not modified.
var original = { name: "Ann", tags: ["a", "b"] };
var updated = { name: "Bob", tags: ["a", "b", "c"] };
var diff = JSONDiff.diff(original, updated);
JSONDiff.patch(original, diff);
// Result (equal to `updated`)
{ "name": "Bob", "tags": ["a", "b", "c"] }
Returns the original structure with every value replaced by {
old, new, type }. Useful for building your own UI.
var original = { name: "Ann", age: 30 };
var diff = JSONDiff.diff(original, { name: "Bob", age: 30, email: "[email protected]" });
JSONDiff.diffPatch(original, diff);
// Result
{
"name": { "type": "CHANGE", "old": "Ann", "new": "Bob" },
"age": { "type": "SAME", "old": 30, "new": 30 },
"email": { "type": "ADD", "old": "", "new": "[email protected]" }
}
Returns an HTML string of nested <ul> lists:
removed/old values are red with strikethrough, added/new values are
green, unchanged values are grey.
var original = { name: "Ann", age: 30 };
var diff = JSONDiff.diff(original, { name: "Bob", age: 30 });
writeOutput( JSONDiff.displayDiff(original, diff) );
var diffs = JSONDiff.diff({a:1},{a:2,b:3});
JSONDiff.summary(diffs);
//Result
{
add: 1,
remove: 0,
change: 1,
update: 0
}
JSONDiff.visualizeDiff({a:1},{a:2});
//Result
<ul><li><span style="font-weight:bold">a</span>: <span style="background: #ffbbbb;text-decoration: line-through;">1</span> <span style="background: #bbffbb;">2</span> (change)</li></ul>
This library is distributed under the apache license, version 2.0
Copyright 2021 Scott Steinbeck; All rights reserved.
Licensed under the apache license, version 2.0 (the "license"); You may not use this library except in compliance with the license. You may obtain a copy of the license at:
http://www.apache.org/licenses/license-2.0
Unless required by applicable law or agreed to in writing, software distributed under the license is distributed on an "as is" basis, without warranties or conditions of any kind, either express or implied.
See the license for the specific language governing permissions and limitations under the license.
All notable changes to this project are documented here. Versions follow box.json.
Only v2.0.0 is tagged in git; other entries are dated from the commit that set the version.
Breaking changes are flagged with ⚠️.
summary(diffs) returns counts of add, remove, change, and update.visualizeDiff(first, second [, ignoreKeys, caseSensitive]) diffs two values and returns the HTML from displayDiff().BigDecimal instead of precisionEvaluate(), so it runs on BoxLang. numericCheck() recognizes Long, Float, Short, and BigDecimal, and ignores null or non-simple values.diffByKey() grouping uses ordered structs so grouped keys keep a stable order.runPatch() accepts arrays as well as structs, so patch() can apply array diffs on BoxLang.visualizeDiff() HTML follows displayDiff(), including JSON serialization and change-type labels.caseSensitive argument (default false) on diff(), diffByKey() and isSame(). New helper isSameSimpleValue(). (#3)testbox is now 6.3.0+13.arguments. scoping (e.g. boolean numericCheck(), boolean isSame(), array diff()).diffPatch() when items are added to arrays.displayDiff()) now serializes object/array changes to JSON for display.diff() handles null values in arrays and objects.diff() results for inputs containing null differ from earlier versions.v2.0.0)patch(original, diff) – applies a diff to a copy of the original.diffpatch(original, diff) – annotates every value as {old, new, type} (SAME for unchanged).displayDiff(original, diff) – returns an HTML view of the changes.runPatch() and diffToHTML().ArraySpec, BasicSpec, diffPatchSpec, displayDiffSpec.diff() / diffByKey() signatures unchanged. Code formatting cleanup.diffByKey() returns a plain value for single-column keys and an array for composite keys (e.g. [48280, 1988]), instead of a joined string ("48280_1988"). Code comparing against the string form must be updated.key field on struct changes in diffByKey() results (PR #2).diffByKey() for arrays and queries.diff() with ignored-keys support, Readme, MIT license (2022-05).prepend instead of unshift).null; numeric check refactored (isNumeric was problematic).diffByKey() (see 1.1.3).caseSensitive where needed.
$
box install jsondiff