JSON Pretty Print and JSON Multi level Collapse Code in Javascript and Python

If you are the type of programmer that deals with JSON objects a lot, you are probably familiar with some online programming tools to print out the JSON in a very “pretty” format. These tools not only make dealing with JSON easier and less frustrating but, I must admit, make it more fun too!

A “JSON viewer” app that I use regularly to “pretty-print” complicated JSON objects is at jsonviewer.stack.hu. The app has a very intuitive interface and is thus really easy to use. You can just copy a JSON object to the front page of the app or pull a JSON object from a remote location and then “format” the json. There are many more helpful JSON viewer apps and extensions that are helpful for viewing JSON.

Have you ever had the problem of trying to “pretty-print” your JSON object in your program or app for users to see, or to “collapse” your multi-level JSON object (which might contain arrays in objects and objects of arrays and …) programmatically into one level? I have certainly. Programmers that usually have these problems regularly use or make RESTFUL api calls — although RESTful “resources” can be transmitted in XML, SOAP, or even YAML, the predominant format on the web is JSON.

“JSON multi-level Collapse” Code in Javascript and Python

I cooked up the “multi-level collapse JSON” algorithm three days ago because I needed to, given a bunch of streaming JSON objects, collapse each JSON object into the most minimal form and then assemble the JSON objects into a CSV file where each JSON object occupies only one line in the CSV. Yes, my program had to first collapse any JSON object (might contain embedded objects or arrays of objects of arrays of objects of…) into a one-level JSON object without losing any information.

“Multi-level collapse” code in Javascript


// CollapseLib by Daniel Alabi (alabidan.me)
// isPlainObject is part of the jQuery source (I modified the method a little)
/**
* Example use:
* complicated = {"dict1key": {"dict2key": [{"dict3key": {"tell":"me"}}]}}
*
* var dict = CollapseLib.collapseDict(collapse);
* console.log(JSON.stringify(dict, undefined, 2));
*
*/
// todo: fix bug with empty plain object
var CollapseLib = {
/**
*
* @warning allowed types for complexDict : {}, [], JS primitives (int, float, or string)
*
* @param complexDict : a JS object that might have inner JS objects and arrays OR
* a JS array that might have inner JS objects and arrays OR
* @param plainDict : a one-level collapse JS object
*/
// if you have an empty object, just return an empty object
collapseDict : function(complexDict) {
// make plain object to return
var plainDict = {}
, sawComplex = false
, subDict;
if (CollapseLib.isPlainObject(complexDict)) {
// if complexDict is a JS object
sawComplex = false;
for (var complexKey in complexDict) {
// if complexDict[complexKey] is an inner dict
if (CollapseLib.isPlainObject(complexDict[complexKey])) {
if (CollapseLib.isEmptyObject(complexDict[complexKey])) {
return complexDict;
}
subDict = complexDict[complexKey];
sawComplex = true;
for (var subKey in subDict) {
plainDict[complexKey+"."+subKey] = CollapseLib.collapseDict(subDict[subKey]);
}
} else if (Array.isArray && Array.isArray(complexDict[complexKey])) {
if (!CollapseLib.isComplexArray(complexDict[complexKey])) {
plainDict[complexKey] = CollapseLib.getStrFromArray(complexDict[complexKey]);
} else {
sawComplex = true;
for (var i = 0; i < complexDict[complexKey].length; i++) {
plainDict[complexKey + "[" + i + "]"] = CollapseLib.collapseDict(complexDict[complexKey][i]);
}
}
} else {
plainDict[complexKey] = CollapseLib.collapseDict(complexDict[complexKey]);
}
}
if (sawComplex) {
return CollapseLib.collapseDict(plainDict);
} else {
return plainDict;
}
} else {
if (Array.isArray && Array.isArray(complexDict)) {
plainDict = {};
// if complexDict is an array
// that contains an inner array or inner plain object
if (CollapseLib.isComplexArray(complexDict)) {
for (var i = 0; i < complexDict.length; i++) {
plainDict["["+i+"]"] = CollapseLib.collapseDict(complexDict[i]);
}
}
return CollapseLib.collapseDict(plainDict);
} else {
return complexDict.toString();
}
}
}
, isComplexArray : function(arr) {
for (var i = 0; i < arr.length; i++) {
if ((Array.isArray && Array.isArray(arr[i]))
|| CollapseLib.isPlainObject(arr[i])) {
return true;
}
}
return false;
}
, getStrFromArray : function(arr) {
return arr.toString();
}
, isPlainObject: function( obj ) {
var hasOwn = Object.prototype.hasOwnProperty;
// Must be an Object.
// Because of IE, we also have to check the presence of the constructor property.
// Make sure that DOM nodes and window objects don't pass through, as well
if ( !obj || typeof obj !== "object" || obj.nodeType) {
return false;
}
try {
// Not own constructor property must be Object
if ( obj.constructor &&
!hasOwn.call(obj, "constructor") &&
!hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
return false;
}
} catch ( e ) {
// IE8,9 Will throw exceptions on certain host objects #9897
return false;
}
// Own properties are enumerated firstly, so to speed up,
// if last one is own, then all properties are own.
var key;
for ( key in obj ) {}
return key === undefined || hasOwn.call( obj, key );
}
, isEmptyObject: function(obj) {
for (var i in obj) {
if (obj.hasOwnProperty(i)) {
return false;
}
}
return true;
}
}

“Multi-level collapse” code in Python


"""
# How to use:
complicated_dict = {"dict1key": {"dict2key": [{"dict3key": {"tell":"me"}}]}}
one_level_dict = makeSimpleDict(complicated_dict)
print one_level_dict
# prints out {'dict1key.dict2key.[0].dict3key.tell': u'me'}
"""
def makeSimpleDict(complex_dict):
"""
@param complex_dict : a python dict that might have inner dicts and arrays OR
a python list that might have inner dicts and arrays OR
a python object that's neither list of dict
@return plain_dict : plain dict that has only one level or a plain python object
"""
# make plain dict that you will return
plain_dict = {}
if isinstance(complex_dict, dict):
# if complex_dict is a dict
# loop through the keys of this complex dict
sawComplex = False
for complex_key in complex_dict:
# if complex_dict[complex_key] is a dict
if isinstance(complex_dict[complex_key], dict):
sub_dict = complex_dict[complex_key]
# loop through the keys of this sub_dict
sawComplex = True
for sub_key in sub_dict:
plain_dict[complex_key+"."+sub_key] = makeSimpleDict(sub_dict[sub_key])
elif isinstance(complex_dict[complex_key], list):
if not isComplexList(complex_dict[complex_key]):
plain_dict[complex_key] = getStrFromList(complex_dict[complex_key])
else:
sawComplex = True
for i in range(len(complex_dict[complex_key])):
plain_dict[complex_key+"["+str(i)+"]"] = makeSimpleDict(complex_dict[complex_key][i])
else:
plain_dict[complex_key] = makeSimpleDict(complex_dict[complex_key])
if sawComplex:
return makeSimpleDict(plain_dict)
else:
return plain_dict
else:
# if not a dict
if isinstance(complex_dict, list):
# if complex_dict is a list
# is complex_dict a list
# that contains a dict or an inner list?
if not isComplexList(complex_dict):
accum = getStrFromList(complex_dict)
plain_dict = accum
else:
# loop through the complex_dict
for i in range(len(complex_dict)):
plain_dict["["+str(i)+"]"] = makeSimpleDict(complex_dict[i])
return makeSimpleDict(plain_dict)
else:
# if neither a list nor a dict
return unicode(complex_dict)
def isComplexList(ls):
for each in ls:
if isinstance(each, dict) or isinstance(each, list):
return True
return False
def getStrFromList(ls):
if isinstance(ls, list):
return ", ".join([unicode(each) for each in ls])
else:
return ls

For example, the output of the “multi-level” algorithm on input the JSON object


{"apiVersion":"2.0","data":{"updated":"2010-01-07T19:58:42.949Z","totalItems":800,"startIndex":1,"itemsPerPage":1,"items":[{"id":"hYB0mn5zh2c","uploaded":"2007-06-05T22:07:03.000Z","updated":"2010-01-07T13:26:50.000Z","uploader":"GoogleDeveloperDay","category":"News","title":"Google Developers Day US – Maps API Introduction","description":"Google Maps API Introduction …","tags":["GDD07","GDD07US","Maps"],"thumbnail":{"default":"http://i.ytimg.com/vi/hYB0mn5zh2c/default.jpg&quot;,"hqDefault":"http://i.ytimg.com/vi/hYB0mn5zh2c/hqdefault.jpg&quot;},"player":{"default":"https://www.youtube.com/watch?v=hYB0mn5zh2c&quot;,"mobile":"https://m.youtube.com/details?v=hYB0mn5zh2c&quot;},"content":{"1":"rtsp://v5.cache3.c.youtube.com/CiILENy…/0/0/0/video.3gp&quot;,"5":"http://www.youtube.com/v/hYB0mn5zh2c?f…&quot;,"6":"rtsp://v1.cache1.c.youtube.com/CiILENy…/0/0/0/video.3gp&quot;},"duration":2840,"aspectRatio":"widescreen","likeCount":171,"rating":4.63,"ratingCount":68,"viewCount":220101,"favoriteCount":201,"commentCount":22,"status":{"value":"restricted","reason":"limitedSyndication"},"accessControl":{"syndicate":"allowed","commentVote":"allowed","rate":"allowed","list":"allowed","comment":"allowed","embed":"allowed","videoRespond":"moderated"}}]}}

is


{
"apiVersion": "2.0",
"data.updated": "2010-01-07T19:58:42.949Z",
"data.totalItems": "800",
"data.startIndex": "1",
"data.itemsPerPage": "1",
"data.items.[0].id": "hYB0mn5zh2c",
"data.items.[0].uploaded": "2007-06-05T22:07:03.000Z",
"data.items.[0].updated": "2010-01-07T13:26:50.000Z",
"data.items.[0].uploader": "GoogleDeveloperDay",
"data.items.[0].category": "News",
"data.items.[0].title": "Google Developers Day US – Maps API Introduction",
"data.items.[0].description": "Google Maps API Introduction …",
"data.items.[0].tags": "GDD07,GDD07US,Maps",
"data.items.[0].thumbnail.default": "http://i.ytimg.com/vi/hYB0mn5zh2c/default.jpg",
"data.items.[0].thumbnail.hqDefault": "http://i.ytimg.com/vi/hYB0mn5zh2c/hqdefault.jpg",
"data.items.[0].player.default": "https://www.youtube.com/watch?v=hYB0mn5zh2c",
"data.items.[0].player.mobile": "https://m.youtube.com/details?v=hYB0mn5zh2c",
"data.items.[0].content.1": "rtsp://v5.cache3.c.youtube.com/CiILENy…/0/0/0/video.3gp",
"data.items.[0].content.5": "http://www.youtube.com/v/hYB0mn5zh2c?f&#8230;",
"data.items.[0].content.6": "rtsp://v1.cache1.c.youtube.com/CiILENy…/0/0/0/video.3gp",
"data.items.[0].duration": "2840",
"data.items.[0].aspectRatio": "widescreen",
"data.items.[0].likeCount": "171",
"data.items.[0].rating": "4.63",
"data.items.[0].ratingCount": "68",
"data.items.[0].viewCount": "220101",
"data.items.[0].favoriteCount": "201",
"data.items.[0].commentCount": "22",
"data.items.[0].status.value": "restricted",
"data.items.[0].status.reason": "limitedSyndication",
"data.items.[0].accessControl.syndicate": "allowed",
"data.items.[0].accessControl.commentVote": "allowed",
"data.items.[0].accessControl.rate": "allowed",
"data.items.[0].accessControl.list": "allowed",
"data.items.[0].accessControl.comment": "allowed",
"data.items.[0].accessControl.embed": "allowed",
"data.items.[0].accessControl.videoRespond": "moderated"
}

“Pretty Print” Code in Javascript

The goal of the “Pretty Print” code is to, given a JSON object (usually used for complicated json objects that’s multi-level and really nested), print the JSON object in a very clear way so that the user sees the embedded arrays, embedded JSON objects, and embedded arrays in objects and vice versa present in the initial parent object.

So for example, the output of the “pretty print” algorithm on input the JSON object below


{"apiVersion":"2.0","data":{"updated":"2010-01-07T19:58:42.949Z","totalItems":800,"startIndex":1,"itemsPerPage":1,"items":[{"id":"hYB0mn5zh2c","uploaded":"2007-06-05T22:07:03.000Z","updated":"2010-01-07T13:26:50.000Z","uploader":"GoogleDeveloperDay","category":"News","title":"Google Developers Day US – Maps API Introduction","description":"Google Maps API Introduction …","tags":["GDD07","GDD07US","Maps"],"thumbnail":{"default":"http://i.ytimg.com/vi/hYB0mn5zh2c/default.jpg&quot;,"hqDefault":"http://i.ytimg.com/vi/hYB0mn5zh2c/hqdefault.jpg&quot;},"player":{"default":"https://www.youtube.com/watch?v=hYB0mn5zh2c&quot;,"mobile":"https://m.youtube.com/details?v=hYB0mn5zh2c&quot;},"content":{"1":"rtsp://v5.cache3.c.youtube.com/CiILENy…/0/0/0/video.3gp&quot;,"5":"http://www.youtube.com/v/hYB0mn5zh2c?f…&quot;,"6":"rtsp://v1.cache1.c.youtube.com/CiILENy…/0/0/0/video.3gp&quot;},"duration":2840,"aspectRatio":"widescreen","likeCount":171,"rating":4.63,"ratingCount":68,"viewCount":220101,"favoriteCount":201,"commentCount":22,"status":{"value":"restricted","reason":"limitedSyndication"},"accessControl":{"syndicate":"allowed","commentVote":"allowed","rate":"allowed","list":"allowed","comment":"allowed","embed":"allowed","videoRespond":"moderated"}}]}}

is


{
"apiVersion": "2.0",
"data": {
"updated": "2010-01-07T19:58:42.949Z",
"totalItems": 800,
"startIndex": 1,
"itemsPerPage": 1,
"items": [
{
"id": "hYB0mn5zh2c",
"uploaded": "2007-06-05T22:07:03.000Z",
"updated": "2010-01-07T13:26:50.000Z",
"uploader": "GoogleDeveloperDay",
"category": "News",
"title": "Google Developers Day US – Maps API Introduction",
"description": "Google Maps API Introduction …",
"tags": [
"GDD07",
"GDD07US",
"Maps"
],
"thumbnail": {
"default": "http://i.ytimg.com/vi/hYB0mn5zh2c/default.jpg",
"hqDefault": "http://i.ytimg.com/vi/hYB0mn5zh2c/hqdefault.jpg"
},
"player": {
"default": "https://www.youtube.com/watch?v=hYB0mn5zh2c",
"mobile": "https://m.youtube.com/details?v=hYB0mn5zh2c"
},
"content": {
"1": "rtsp://v5.cache3.c.youtube.com/CiILENy…/0/0/0/video.3gp",
"5": "http://www.youtube.com/v/hYB0mn5zh2c?f&#8230;",
"6": "rtsp://v1.cache1.c.youtube.com/CiILENy…/0/0/0/video.3gp"
},
"duration": 2840,
"aspectRatio": "widescreen",
"likeCount": 171,
"rating": 4.63,
"ratingCount": 68,
"viewCount": 220101,
"favoriteCount": 201,
"commentCount": 22,
"status": {
"value": "restricted",
"reason": "limitedSyndication"
},
"accessControl": {
"syndicate": "allowed",
"commentVote": "allowed",
"rate": "allowed",
"list": "allowed",
"comment": "allowed",
"embed": "allowed",
"videoRespond": "moderated"
}
}
]
}
}

The “pretty print” code in Javascript

It’s just a simple line of JS but not many people know about how to pretty print using an already existing function in JS.


JSON.stringify(objectToPrettyPrint, undefined, 2);

For more information, check out the MDN Docs

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s