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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
# 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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{"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…","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"}}]}} |
is
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"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…", | |
"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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{"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…","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"}}]}} |
is
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"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…", | |
"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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
JSON.stringify(objectToPrettyPrint, undefined, 2); |
For more information, check out the MDN Docs