Andrea Bisello
Andrea Bisello

Reputation: 1225

how to replace a values of a dict searching in every deep in order to understand if two json are equal?

i have tried to solve my problem studing this and this and several other pages but i'm not able to understand. I hope i will ask something new.

I try to explain the problem because i don't known the right way to solve it.

I make two requests with requests.get to obtain two json answer from the same api of two version of the same sdk. I want to understand if those json are equal but i want to "whitelist" some values thats i known it will be different (for example creation timestamp).

To do this i want to replace some values of the same keys with the same values in order to ignore difference inside some keys.

For example /server/v1/api.php response is :

{
    "result" : "OK",
    "data" : {
        "text" : "someText",
        "array" : [
            "foo", "bar"
        ],
        "dateTime" : "24/10/2015 22:14"
    }
}

and /server/v2/api.php response is :

{
    "result" : "OK",
    "data" : {
        "text" : "someText",
        "array" : [
            "foo", "bar"
        ],
        "dateTime" : "24/10/2015 22:15"
    }
}

Now I want to "whitelist" dateTime thats because it's normal that it values will change.

How to replace values of a key at every deep? I need to obtain

{
    "result" : "OK",
    "data" : {
        "text" : "someText",
        "array" : [
            "foo", "bar"
        ],
        "dateTime" : "whitelisted"
    }
}

so the two json will be equal.

in the real case i DON'T known json structure and I NEED to USE a hardcoded whitelist to filter the test result so i need to iterate over the json in order to apply the whitelist.

this is a real example

d1 = {
   "ssoCode": "OK",
   "errorDescription": "",
   "content": {
        "xcontentId": "508e5d95-2267-4408-b801-3742819a6d98",
        "creationDate": "2015-10-26T16: 16: 07.504Z",
        "sourcefilesOldVersions": [],
        "id": "b37412ee-b7de-4642-9d38-ae336e030f77",
        "userId": "andrea.bisello",
        "owner": "twin",
        "contentType": "PAGELET",
        "solution": "VIEW",
        "availableInSolutions": [
            "VIEW"
        ],
        "sourceFiles": [],
        "packagedId": [],
        "channels": [
            {
                "status": "PUBLISHED",
                "channelType": "WEB",
                "startTime": "2015-10-26T16: 16: 07.707Z",
                "finishTime": "2015-10-26T16: 16: 07.723Z"
            }
        ],
        "xpublishedId": "0ad653cc-664a-4d36-8b9e-b7788a43a3b4"
    },
    "resultCode": "OK",
    "actionsInError": []
}

update :

as suggested by Letzerwille i should use dict.update() to apply whitelist. How to apply to dict contained in my first dict without removing other keys? for example this is my whitelist dict

whitelist = {
    "content": {
        "xcontentId": "whitelisted",
        "creationDate": "whitelisted",
        "id": "whitelisted",
        "channels": [
            {
                "startTime": "whitelisted",
                "finishTime": "whitelisted"
            }
        ],
        "xpublishedId": "whitelisted"
    }
}

it keeps all the keys that i want "to whitelist".

but applying this dict i will destroy every other keys of "content" dict, because the entire "content" keys will be overwritten by the new one so i lost, for example, ["content"]["owner"] that should not be removed (this is the result)

{
    "ssoCode": "OK",
    "actionsInError": [],
    "errorDescription": "",
    "resultCode": "OK",
    "content": {
        "creationDate": "whitelisted",
        "id": "whitelisted",
        "xcontentId": "whitelisted",
        "xpublishedId": "whitelisted",
        "channels": [
            {
                "startTime": "whitelisted",
                "finishTime": "whitelisted"
            }
        ]
    }
}

how i can solve this problem?

so i tried to make a function with receive a dict and a whitelist (for example whitelist = ["id"] ) but something during the iteration of the list doesn't work and it return a corrupted object (thats because entering in the list switch case, the function exit)

def applyWhitelist(something, whitelist):
    print(something)
    if isinstance(something, dict):
        for k, v in something.items():
            print(k, v)
            if isinstance(v, str):
                if k in whitelist:
                    something[k] = "whitelisted"
            if isinstance(v, int):
                if k in whitelist:
                    something[k] = "whitelisted"
            if isinstance(v, dict):
                return applyWhitelist(something[k], whitelist)
            if isinstance(v, list):
                if len(v) > 0:
                    return applyWhitelist(something[k], whitelist)
    if isinstance(something, list):
        for el in something:
            if isinstance(el, dict):
                return applyWhitelist(el, whitelist)
            if isinstance(el, list):
                if len(el) > 0:
                    return applyWhitelist(el, whitelist)
            if isinstance(el, str):
                if el in whitelist:
                    el = "whitelisted"
            if isinstance(el, int):
                if el in whitelist:
                    el = "whitelisted"
    if isinstance(something, str):
        if something in whitelist:
            something = "whitelisted"
    if isinstance(something, int):
        if something in whitelist:
            something = "whitelisted"

Is my way the best way to obtain that result? any suggestions?

Upvotes: 0

Views: 103

Answers (1)

LetzerWille
LetzerWille

Reputation: 5668

    to whitelist use update. say you what to whitelist d.

     d = {
           "ssoCode": "OK",
           "errorDescription": "",
           "content": {
                "xcontentId": "508e5d95-2267-4408-b801-3742819a6d98",
                "creationDate": "2015-10-26T16: 16: 07.504Z",
                "sourcefilesOldVersions": [],
                "id": "b37412ee-b7de-4642-9d38-ae336e030f77",
                "userId": "andrea.bisello",
                "owner": "twin",
                "contentType": "PAGELET",
                "solution": "VIEW",
                "availableInSolutions": [
                    "VIEW"
                ],
                "sourceFiles": [],
                "packagedId": [],
                "channels": [
                    {
                        "status": "PUBLISHED",
                        "channelType": "WEB",
                        "startTime": "2015-10-26T16: 15: 07.707Z",
                        "finishTime": "2015-10-26T16: 16: 07.723Z"
                    }
                ],
                "xpublishedId": "0ad653cc-664a-4d36-8b9e-b7788a43a3b4"
            },
            "resultCode": "OK",
            "actionsInError": []
        }

    change the value that need to be whitlisted. Here I have changed  "startTime" to "=========================="


        d_update = {
           "ssoCode": "OK",
           "errorDescription": "",
           "content": {
                "xcontentId": "508e5d95-2267-4408-b801-3742819a6d98",
                "creationDate": "2015-10-26T16: 16: 07.504Z",
                "sourcefilesOldVersions": [],
                "id": "b37412ee-b7de-4642-9d38-ae336e030f77",
                "userId": "andrea.bisello",
                "owner": "twin",
                "contentType": "PAGELET",
                "solution": "VIEW",
                "availableInSolutions": [
                    "VIEW"
                ],
                "sourceFiles": [],
                "packagedId": [],
                "channels": [
                    {
                        "status": "PUBLISHED",
                        "channelType": "WEB",
                        "startTime": "==========================",
                        "finishTime": "2015-10-26T16: 16: 07.723Z"
                    }
                ],
                "xpublishedId": "0ad653cc-664a-4d36-8b9e-b7788a43a3b4"
            },
            "resultCode": "OK",
            "actionsInError": []
        }

    Now run update command on dictionary you want to make that change.

    d.update(d_update)

    pp(d)


    {'actionsInError': [],
     'content': {'availableInSolutions': ['VIEW'],
                 'channels': [{'channelType': 'WEB',
                               'finishTime': '2015-10-26T16: 16: 07.723Z',
                               'startTime': '==========================',
                               'status': 'PUBLISHED'}],
                 'contentType': 'PAGELET',
                 'creationDate': '2015-10-26T16: 16: 07.504Z',
                 'id': 'b37412ee-b7de-4642-9d38-ae336e030f77',
                 'owner': 'twin',
                 'packagedId': [],
                 'solution': 'VIEW',
                 'sourceFiles': [],
                 'sourcefilesOldVersions': [],
                 'userId': 'andrea.bisello',
                 'xcontentId': '508e5d95-2267-4408-b801-3742819a6d98',
                 'xpublishedId': '0ad653cc-664a-4d36-8b9e-b7788a43a3b4'},
     'errorDescription': '',
     'resultCode': 'OK',
     'ssoCode': 'OK'}


to find the value which is different use:

def dict_comp(d1, d2):
    # compare dicts with identical structure
    # return True if identical values,
    # return False if a value is different
    if d1 == d2:
        return True
    else:
        for (k1, v1), (k2, v2) in zip(sorted(d1.items()), sorted(d2.items())):
            if k1 == k2:
                if isinstance(v1, dict):
                    return dict_comp(v1, v2)
                else:
                    if v1 == v2:
                        pass
                    else:
                        print("different values found at key --> "
                              "{} <-- {} {} ".format(k1, v1, v2))
                        return False

Upvotes: 2

Related Questions