יום ראשון, 8 בספטמבר 2019

פרסור Json המכיל keys כפולים (python)

Json With Duplicate Keys

לאחרונה הייתי צריך לקרוא קובץ json שמסיבה כלשהי היו בו כמה מפתחות כפולים.

לדוגמה:
{
    "field-A": {
        "title""example title",
        "some-array": ["GML""XML"],
        "duplic-dict": {"A""4""A""5""B"2"C""3""B""11""B"300},
        "empty-dict": {},
        "more": {
            "title""S",
            "field-AA": {
                "duplic-field-AB": {
                    "ID""1234",
                    "ID""56",
                    "SortAs""Text"
                }
            }
        }
    }
}



כמובן שה-parser הרגיל לא עובד במקרה כזה. הגענו בצוות למסקנה שיהיה הכי פשוט אם נשים ערכים של מפתחות כפולים במערך אחד בעל שם המפתח הכפול. בהתבסס על הנושא הזה ב-stackoverflow, זה הפתרון הסופי שכתבתי, ולשמחתי הוא פשוט מאוד:


import json

def parse_duplicable_object_pairs(pairs):
    """Scan json as usual, but where there are duplicate keys convert them to array.
    Example:
        From: {'dd': {'A': '4', 'A': '5', 'B': 2, 'C': '3', 'B': '11', 'B': '50'}} 
        To:   {'dd': {'A': ['4', '5'], 'C': '3', 'B': [2, '11', '50']}}

    """
    keys = [key for key, value in pairs]
    # If there are no duplic keys, return regular dict
    if len(keys) == len(set(keys)):
        return {key: value for key, value in pairs}
    else:
        mixed_dict = {}
        for key, value in pairs:
            if key not in mixed_dict:
                mixed_dict[key] = value
            else:
                if not isinstance(mixed_dict[key], list):
                    mixed_dict[key] = [mixed_dict[key], value]
                else:
                    mixed_dict[key].append(value)
        return mixed_dict

jp = r"C:\Users\noamn\Desktop\BadJson.json" 
with open(jp, "r"as json_file:
    json_data = json.load(json_file, object_pairs_hook=parse_duplicable_object_pairs)
    print (json_data)

התוצאה במקרה הזה תהיה:

{
    "field-A": {
        "title""example title",
        "some-array": ["GML""XML"],
        "duplic-dict": {"A"["4""5"]"B"[2"11", 300]"C""3"},
        "empty-dict": {},
        "more": {
            "title""S",
            "field-AA": {
                "duplic-field-AB": {
                    "ID"["1234""56"],
                    "SortAs""Text"
                }
            }
        }
    }
}



וזה הכל בעצם.