Json Diffing Discussion

OK. My ordering() function was buggy. This is better:

# Human-friendly and git-friendly (deterministically diffable) JSON encoding.

from java.util import TreeMap
from com.inductiveautomation.ignition.common.util import Comparators
from com.inductiveautomation.ignition.common.gson import GsonBuilder

ciAlnumCmp = Comparators.alphaNumeric(False)

# 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.
def ordering(subject, listKey='name'):
	if hasattr(subject, 'items'):
		subst = TreeMap(ciAlnumCmp)
		for k, v in subject.items():
			subst[k] = ordering(v)
		return subst
	if hasattr(subject, '__iter__'):
		# Use a generator to exit quickly if any element of the
		# list-like object is *not* a dictionary-like object.
		if listKey and all(hasattr(inner, 'items') for inner in subject):
			reordered = TreeMap(ciAlnumCmp)
			reordered.update([(x.get(listKey, str(i)), ordering(x)) for (i, x) in enumerate(subject)])
			return reordered.values()
		return [ordering(x) for x in subject]
	return subject
#

#
def orderedJson(source):
	json = system.util.jsonDecode(source)
	ordered = ordering(json)
	gson = GsonBuilder().setPrettyPrinting().create()
	return gson.toJson(ordered)
#

def test():
	original = {'a8': 0.9, 'a9': 1, 'A10': 1.1, 'A12':1.2, 'a11': [4, 5, 6]}
	ordered = jsonUtil.ordering(original)
	print "Ordered:"
	print repr(ordered)
	print "Using system.util.jsonEncode():"
	print system.util.jsonEncode(dict(_=ordered), 2)[6:-1]
	print "Using Gson:"
	gson = GsonBuilder().setPrettyPrinting().create()
	print gson.toJson(ordered)
#

Running someScript.test() in the script console yields this:

Ordered:
{u'a8': 0.9, u'a9': 1, u'A10': 1.1, u'a11': [4, 5, 6], u'A12': 1.2}
Using system.util.jsonEncode():
{
  "A10": 1.1,
  "A12": 1.2,
  "a11": [
    4,
    5,
    6
  ],
  "a8": 0.9,
  "a9": 1
}
Using Gson:
{
  "a8": 0.9,
  "a9": 1,
  "A10": 1.1,
  "a11": [
    4,
    5,
    6
  ],
  "A12": 1.2
}
>>>

Much better.

Also lets you disable list re-ordering, or use a different key.

4 Likes