Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to completely sort a JSON tree alphabetically

I need to do a complete recursive alphabetical ordering on a JSON object in python.

The reason is to be able to diff two json files.

Given this input:

{
    "request-id": "12345",
    "version": "1.1.4",
    "multi": {
            "one": 1, 
            "two": 2.0,
            "Abc": [3,2,4,1, null],
            "three": null,
            "list": [
                        {"lb1": 2.1},
                        {"lb": 2.2}, 
                        {"la": 3}, 
                        {"mix_list": [1, {"bb":1}, 2, {"aa":1}]}]
        }
}

this is the expected output:

{
    "multi": {
        "Abc": [1,2,3,4,null],
        "list": [
            {"la": 3},
            {"lb": 2.2},
            {"lb1": 2.1},
            { "mix_list": [1, 2, {"aa": 1}, {"bb": 1}] }
        ],
        "one": 1,
        "three": null,
        "two": 2.0
    },
    "request-id": "12345",
    "version": "1.1.4"
}

EDIT: to be able to do a diff it should order the array elements too.

like image 835
lorenzo Avatar asked Oct 31 '25 16:10

lorenzo


1 Answers

A JSON object is a simple dict object. Before version 3.7 dicts had no ordering so you first need to convert it to an OrderedDict and then append each json element in the correct order. With 3.7+ you can rely on the standard dict ordering.

Objects with keys are sorted according to their keys, objects inside a list are sorted by their "sorted recursive string representation" while primitive values are sorted according to their natural ordering.

import json
from operator import itemgetter

# replace all three {} with OrderedDict() for python <= 3.6

def sorted_json(js, result):

    def norm_str(s):
        # because of str special handling of single quotes
        return str(s).replace("'", '"')

    if type(js) in [int, str, bool, float] or js is None:
        return js

    if type(js) == list:
        res = [sorted_json(i, {}) for i in js]
        return sorted(res, key=norm_str)

    items = sorted(js.items(), key=itemgetter(0))
    for k, v in items:
        result[k] = sorted_json(v, {})

    return result

The sorting is case sensitive.

You can use it in this way:

json_data = json.loads(json_text)
res = sorted_json(json_data, {})
print(json.dumps(res, indent=4))
like image 162
lorenzo Avatar answered Nov 03 '25 07:11

lorenzo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!