5

I have nested json as below

{
"product" : "name",
"protocol" : "scp",
"read_logs" : {
    "log_type" : "failure",
    "log_url" : "htttp:url"
    }
}

I am trying to create Python class object with the below code.

import json
class Config (object):
    """
    Argument: JSON Object from the configuration file.
    """
   def __init__(self, attrs):
        if 'log_type' in attrs:
            self.log_type = attrs['log_type']
            self.log_url = attrs['log_url']
        else:
           self.product = attrs["product"]
           self.protocol = attrs["protocol"]
   def __str__(self):
       return "%s;%s" %(self.product, self.log_type)

   def get_product(self):
        return self.product

   def get_logurl(self):
       return self.log_url

class ConfigLoader (object):
    '''
        Create a confiuration loaded which can read JSON config files
    '''
    def load_config (self, attrs):
        with open (attrs) as data_file:
            config = json.load(data_file, object_hook=load_json)
        return config

def load_json (json_object):
    return Config (json_object)

loader = ConfigLoader()
config = loader.load_config('../config/product_config.json')

print config.get_protocol()

But, the object_hook is invoking the load_json recursively and the Class Config init is being called twice. So the final object that I created does not contain the nested JSON data.

Is there any way to read the entire nested JSON object into a single Python class ?

Thanks

3 Answers 3

10

A variation on Pankaj Singhal's idea, but using a "generic" namespace class instead of namedtuples:

import json

class Generic:
    @classmethod
    def from_dict(cls, dict):
        obj = cls()
        obj.__dict__.update(dict)
        return obj

data = '{"product": "name", "read_logs": {"log_type": "failure", "log_url": "123"}}'

x = json.loads(data, object_hook=Generic.from_dict)
print(x.product, x.read_logs.log_type, x.read_logs.log_url)
Sign up to request clarification or add additional context in comments.

Comments

4

namedtuple & object_hook can help create a one-liner:

# Create an object with attributes corresponding to JSON keys.
def json_to_obj(data): return json.loads(data, object_hook=lambda converted_dict: namedtuple('X', converted_dict.keys())(*converted_dict.values()))

OR Create a more readable function like below:

def _object_hook(converted_dict): return namedtuple('X', converted_dict.keys())(*converted_dict.values())
def json_to_obj(data): return json.loads(data, object_hook=_object_hook)

Below is the code snippet to use it:

import json
from collections import namedtuple

data = '{"product": "name", "read_logs": {"log_type": "failure", "log_url": htttp:url}}'

x = json_to_obj(data)
print x.product, x.read_logs.log_type, x.read_logs.log_url

NOTE: Check out namedtuple's rename parameter.

1 Comment

Using namedtuples isn't the semantically best option, not to mention creating new namedtuples is fairly slow due to class creation.
1

I wrote a simple DFS algorithm to do this job.

Convert nested item as a flat dictionary. In my case, I joined the keys of json item with a dash.

For example, nested item { "a":[{"b": "c"}, {"d":"e"}] } will be transformed as {'a-0-b': 'c', 'a-1-d': 'e'}.

def DFS(item, headItem, heads, values):
    if type(item) == type({}):
        for k in item.keys():
            DFS(item[k], headItem + [k], heads, values)
    elif type(item) == type([]):
        for i in range(len(item)):
            DFS(item[i], headItem + [str(i)], heads, values)
    else:
        headItemStr = '-'.join(headItem)
        heads.append(headItemStr)
        values.append(item)
    return


def reduce(jsonItem):
    heads, values = [], []
    DFS(jsonItem, [], heads, values)
    return heads, values


def json2dict(jsonItem):
    head, value = reduce(jsonItem)
    dictHeadValue = { head[i] : value[i] for i in range(len(head))}
    return dictHeadValue

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.