简体   繁体   中英

How to compare two json objects to check what has changed?

I have two json objects as below:

json.json

{
    "access_points": [
        {
            "ssid": "MyAP",
            "snr": 63,
            "channel": 11
        },
        {
            "ssid": "YourAP",
            "snr": 42,
            "channel": 1
        },
        {
            "ssid": "HisAP",
            "snr": 54,
            "channel": 6
        }
    ]
}

json_.json

{
    "access_points": [
        {
            "ssid": "MyAP",
            "snr": 82,
            "channel": 11
        },
        {
            "ssid": "YourAP",
            "snr": 42,
            "channel": 6
        },
        {
            "ssid": "HerAP",
            "snr": 71,
            "channel": 1
        }
    ]
}

And as you can see above, the values have changed a bit as:

  1. MyAP's SNR has changed from 63 to 82
  2. YourAP's channel has changed from 1 to 6
  3. HisAP is removed from the list
  4. HerAP is added to the list with SNR 71 and channel 1

I need to track the above and my expected output should be:

Following items have changed: ==========================


1. MyAP’s SNR has changed from 63 to 82
2. YourAP’s channel has changed from 1 to 6
3. HisAP is removed from the list
4. HerAP is added to the list with SNR 71 and channel 1
========================================================

This is what I have been trying to compare the keys but I am stuck how I can compare each nested values:

def checkIfEquals(obj):
    if isinstance(obj, dict):
        return sorted((k, checkIfEquals(v)) for k, v in obj.items())
    if isinstance(obj, list):
        return sorted(checkIfEquals(x) for x in obj)
    else:
        return obj

def test():

    # JSON string
    with open('/Users/jananath/Desktop/Int/tmp/json.json') as data_file:   
        one = json.load(data_file)
    
    with open('/Users/jananath/Desktop/Int/tmp/json_.json') as data_file:   
        two = json.load(data_file)
    

    areTheytheSame = checkIfEquals(one) == checkIfEquals(two)

    if areTheytheSame:
        print("Same")
    else:
        for key in two.keys():
            value = two[key] 
            if key not in one:
                print("found new key {0} with value {1}".format(key, value))
            else:
            #check if values are not same
                if one[key] != value: print("for key %s values are different" % key)

Can someone please help?

My code works only with structure which you show in example data.

As for me checkIfEquals is useless because it doesn't create structure which I could use to get detailed differences. It still need to work with original data for this. And this way I could simply set at start the_same = True and compare elements one-by-one and when there is difference then display it and set the_same = True . If at the end I have the_same = False then I can print The same

But it is simple when to get access_points as dictionaries

one: {'MyAP': {'snr': 63, 'channel': 11}, 'YourAP': {'snr': 42, 'channel': 1}, 'HisAP': {'snr': 54, 'channel': 6}}
two: {'MyAP': {'snr': 82, 'channel': 11}, 'YourAP': {'snr': 42, 'channel': 6}, 'HerAP': {'snr': 71, 'channel': 1}}

because now I can get all keys ( ssid ) and convert to set() and check which are added, which removed and which are in both.

one_keys = set(one.keys())
two_keys = set(two.keys())

only_one = sorted(one_keys - two_keys)
only_two = sorted(two_keys - one_keys)
both     = sorted(one_keys & two_keys)

And later I can use only_one to display removed item, only_two to display added items, and both to compare snr , channel and display differences.


Full working code:

one = {
    "access_points": [
        {
            "ssid": "MyAP",
            "snr": 63,
            "channel": 11
        },
        {
            "ssid": "YourAP",
            "snr": 42,
            "channel": 1
        },
        {
            "ssid": "HisAP",
            "snr": 54,
            "channel": 6
        }
    ]
}

two = {
    "access_points": [
        {
            "ssid": "MyAP",
            "snr": 82,
            "channel": 11
        },
        {
            "ssid": "YourAP",
            "snr": 42,
            "channel": 6
        },
        {
            "ssid": "HerAP",
            "snr": 71,
            "channel": 1
        }
    ]
}

# --- functions ---

def get_access_points(data):
    result = {}
    for item in data["access_points"]:
        name = item['ssid']
        item.pop('ssid')
        result[name] = item
    return result

# --- main ---
    
one = get_access_points(one)
two = get_access_points(two)
print('one:', one)
print('two:', two)
print('---')

one_keys = set(one.keys())
two_keys = set(two.keys())

only_one = sorted(one_keys - two_keys)
only_two = sorted(two_keys - one_keys)
both = sorted(one_keys & two_keys)
print('only_one:', only_one)
print('only_two:', only_two)
print('both    :', both)
print('---')

the_same = True

for key in both:
    item1 = one[key]
    item2 = two[key]
    if item1["snr"] != item2["snr"]:
        print(f'{key:10} | changed | SNR from {item1["snr"]} to {item2["snr"]}')
        the_same = False
    if item1["channel"] != item2["channel"]:
        print(f'{key:10} | changed | CHANNEL from {item1["channel"]} to {item2["channel"]}')
        the_same = False

for key in only_one:
    item = one[key]    
    print(f'{key:10} | removed | with SNR {item["snr"]} and CHANNEL {item["channel"]}')
    the_same = False    

for key in only_two:
    item = two[key]
    print(f'{key:10} | added   | with SNR {item["snr"]} and CHANNEL {item["channel"]}')
    the_same = False    

if the_same:
    print('The same')

Result:

one: {'MyAP': {'snr': 63, 'channel': 11}, 'YourAP': {'snr': 42, 'channel': 1}, 'HisAP': {'snr': 54, 'channel': 6}}
two: {'MyAP': {'snr': 82, 'channel': 11}, 'YourAP': {'snr': 42, 'channel': 6}, 'HerAP': {'snr': 71, 'channel': 1}}
---
only_one: ['HisAP']
only_two: ['HerAP']
both    : ['MyAP', 'YourAP']
---
MyAP       | changed | SNR from 63 to 82
YourAP     | changed | CHANNEL from 1 to 6
HisAP      | removed | with SNR 54 and CHANNEL 6
HerAP      | added   | with SNR 71 and CHANNEL 1

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM