Skip to main content

Diffable JSON Strings

If you need a JSON object/string to be consistently ordered regardless of how it was built or ordered in memory, the following script can help force it to be organized/ordered alphabetically so that it can be used with source control tools or use diff tools to compare different outputs to one another.

# Functions designed to be called via objectScript() in UI expressions.

# Requires the Automation Toolkit by Automation Professionals (Phil Turmel)

from java.io import File
from java.lang import System, Throwable
from java.util import TreeMap
from com.inductiveautomation.ignition.common.util import Comparators
loggerfrom =com.inductiveautomation.ignition.common.gson system.util.getLogger(system.util.getProjectName()import + '.' + system.reflect.getModulePath())
tkCtx = system.util.toolkitCtx()GsonBuilder

ciAlnumCmp = Comparators.alphaNumeric(True)False)

def __ordering(subject)subject, listKey='name'):
	''''
	Deep copy with conversion of maps to key-ordered maps and
	conversion of lists-of-dicts that contain a 'name' key into
	ordered lists.
	Keys other than "name" may be supplied, or None to disable
	re-ordering lists of dictionaries.
	'''
	if hasattr(subject, 'items'):
		subst = TreeMap(ciAlnumCmp)
		for k, v in subject.items():
			subst[k] = __ordering(v)
		return subst
	firstif =hasattr(subject, None'__iter__'):
		try:# firstUse =a subject[0]generator except:to passexit try:quickly if firstany element of the
		# list-like object is *not* a dictionary-like object.
		if listKey and all(hasattr(first,inner, 'items') for inner in subject):
			substreordered = TreeMap(ciAlnumCmp)
			subst.reordered.update([(x.get('name',listKey, str(i)), __ordering(x)) for (i, x) in enumerate(subject)])
			return reordered.values()
		return [x__ordering(x) for x in subst.values()]
	except Throwable, t:
		logger.info("Java failure in ordering:", t)
	except Exception, e:
		logger.info("Jython failure in ordering:", system.reflect.asThrowable(e, None))subject]
	return subject
	
def orderedJson(json)json, useGson = True):
	'''
    Re-orders a JSON string alphabetically so it can be use with diff tools or other source control tools

	Args:
		json (str): JSON Dictionary as a string to be re-ordered
		useGson (bool): Use Google's Gson library to pretty-print the JSON

	Returns:
		str: Re-ordered JSON string
		
     '''
	source = system.util.jsonDecode(json)
	ordered = __ordering(source)

	if useGson:
		gson = GsonBuilder().setPrettyPrinting().create()
		return gson.toJson(ordered)
	else:
		return system.util.jsonEncode(dict(_=ordered), 2)[6:-1]

Source slightly tweaked from: https://forum.inductiveautomation.com/t/json-diffing-discussion/96800