Encoding a python nested object in JSON

I want to encode objects in JSON. But I can’t figure out how to make a conclusion without crowding out the line.

import json class Abc: def __init__(self): self.name="abc name" def toJSON(self): return json.dumps(self.__dict__, cls=ComplexEncoder) class Doc: def __init__(self): self.abc=Abc() def toJSON(self): return json.dumps(self.__dict__, cls=ComplexEncoder) class ComplexEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, Abc) or isinstance(obj, Doc): return obj.toJSON() else: return json.JSONEncoder.default(self, obj) doc=Doc() print doc.toJSON() 

Result (dumps return a string representation, so they are "escaped")

 {"abc": "{\"name\": \"abc name\"}"} 

I want something a little different. Expected Result:

 {"abc": {"name": "abc name"}"} 

But I do not see how ... Any hint?

early.

+27
json python encode
Mar 01 '11 at 20:40
source share
5 answers

my previous sample, with another nested object and your advice:

 import json class Identity: def __init__(self): self.name="abc name" self.first="abc first" self.addr=Addr() def reprJSON(self): return dict(name=self.name, firstname=self.first, address=self.addr) class Addr: def __init__(self): self.street="sesame street" self.zip="13000" def reprJSON(self): return dict(street=self.street, zip=self.zip) class Doc: def __init__(self): self.identity=Identity() self.data="all data" def reprJSON(self): return dict(id=self.identity, data=self.data) class ComplexEncoder(json.JSONEncoder): def default(self, obj): if hasattr(obj,'reprJSON'): return obj.reprJSON() else: return json.JSONEncoder.default(self, obj) doc=Doc() print "Str representation" print doc.reprJSON() print "Full JSON" print json.dumps(doc.reprJSON(), cls=ComplexEncoder) print "Partial JSON" print json.dumps(doc.identity.addr.reprJSON(), cls=ComplexEncoder) 

gives the expected result:

 Str representation {'data': 'all data', 'id': <__main__.Identity instance at 0x1005317e8>} Full JSON {"data": "all data", "id": {"name": "abc name", "firstname": "abc first", "address": {"street": "sesame street", "zip": "13000"}}} Partial JSON {"street": "sesame street", "zip": "13000"} 

Thank.

+29
Mar 02 2018-11-11T00:
source share

So, the immediate problem is that you are passing the json module a JSON value that will be encoded as another line in the JSON value.

The broader problem is that you greatly exaggerate this.

Using the JSON datetime between Python and JavaScript , I would go with something closer to this:

 import json class Abc: def __init__(self): self.name="abc name" def jsonable(self): return self.name class Doc: def __init__(self): self.abc=Abc() def jsonable(self): return self.__dict__ def ComplexHandler(Obj): if hasattr(Obj, 'jsonable'): return Obj.jsonable() else: raise TypeError, 'Object of type %s with value of %s is not JSON serializable' % (type(Obj), repr(Obj)) doc=Doc() print json.dumps(doc, default=ComplexHandler) 

who gets you:

 ~$ python nestjson.py {"abc": "abc name"} ~$ 

This can be made cleaner / safer / safer (in particular, just capturing __dict__ usually not recommended to do external debugging / troubleshooting), but it should get the point. All you need, in principle, is a way to get a json-compatible object (whether it's a simple string or number or list or dict) from each "node" in the tree. This object should not be the JSON-serialized object you are already doing.

+18
Mar 01 '11 at 21:00
source share

To avoid code repetition, as in Fred Laurent, I overloaded the __iter__() method as follows. It also allows you to "jsonize" the list, datetime and decimal elements without any additional dependencies, just use dict ().

 import datetime import decimal class Jsonable(object): def __iter__(self): for attr, value in self.__dict__.iteritems(): if isinstance(value, datetime.datetime): iso = value.isoformat() yield attr, iso elif isinstance(value, decimal.Decimal): yield attr, str(value) elif(hasattr(value, '__iter__')): if(hasattr(value, 'pop')): a = [] for subval in value: if(hasattr(subval, '__iter__')): a.append(dict(subval)) else: a.append(subval) yield attr, a else: yield attr, dict(value) else: yield attr, value class Identity(Jsonable): def __init__(self): self.name="abc name" self.first="abc first" self.addr=Addr() class Addr(Jsonable): def __init__(self): self.street="sesame street" self.zip="13000" class Doc(Jsonable): def __init__(self): self.identity=Identity() self.data="all data" def main(): doc=Doc() print "-Dictionary- \n" print dict(doc) print "\n-JSON- \n" print json.dumps(dict(doc), sort_keys=True, indent=4) if __name__ == '__main__': main() 

Exit:

 -Dictionary- {'data': 'all data', 'identity': {'first': 'abc first', 'addr': {'street': 'sesame street', 'zip': '13000'}, 'name': 'abc name'}} -JSON- { "data": "all data", "identity": { "addr": { "street": "sesame street", "zip": "13000" }, "first": "abc first", "name": "abc name" } } 

Hope this helps! Thanks

+4
Jan 31 '15 at 16:11
source share

I could not add this as a comment and add as an answer. The latest Fred example was useful to me. I was told that jsonpickle does this, but was unable to install the module for proper installation and launch. Therefore, the code is used here. However, despite the small changes, I had too many variables to add manually to some objects. So this little loop simplified:

 def reprJSON(self): d = dict() for a, v in self.__dict__.items(): if (hasattr(v, "reprJSON")): d[a] = v.reprJSON() else: d[a] = v return d 

It can be used in any object with a subclass that is too busy for manual coding. Or it can become an assistant for all classes. This also works for the full representation of JSON member arrays that contain other classes (provided that they implement repJSON (), of course).

+2
Apr 20 '12 at 23:28
source share

This is what you are looking for: https://github.com/jsonpickle/jsonpickle

It embeds serialization of Python objects and can be easily extended to serialize custom types.

+1
Sep 19 '14 at 0:40
source share



All Articles