User:LepreKhaun Resident/Json Pretty Printer

From Second Life Wiki
Jump to navigation Jump to search

[NOTE: Pages within my Name Space are a WIP and constantly changing. As my understanding of the problems I attempt to address and the grasp of the subject matter itself deepens, I regularly review what I have written and update the content as better algorithms occur to me.

However, for this process of refinement, improvement and tweaking to result in something that might (hopefully!) benefit the community at large, I ask that comments, suggested improvements, corrections of fact or your own personal style preferences be made ONLY on the Discussion Pages within my Name Space. Thank you!]

JsonPrettyChat.lsl - a JSON Pretty Printer

This is a stand alone debugging tool for working with JSON text. It acts like all JSON pretty printers and outputs to llOwnerSay(). This is NOT a JSON validator, meaning it may well "pretty print" your string even if your strings within it are mal-formed json constructions (such as having "\s" within it or empty values such as "[,,,]", which breaks strict JSON compliance). But, it will separate your strings out for visual inspection.

It uses recursion A LOT so will likely crash if you have a very large JSON structure. However, it'll have worked it up to a point where you can determine where it hit the stack heap collision, and you simply need to break parts of the JSON string out to continue deeper into it. (No longer true with V2.0!)

It expects a link message with the JSON string as the third parameter. The second parameter is used as a "channel ID" (defaults to 75 as written). If this conflicts with your existing link messaging system, I'd expect you should see how to modify the code to suit yourself.

////////////////////////////////////////////////////
//    JsonPrettyChat.lsl
//
//    A debugging tool for Json construction
//    Version 2.0 by LepreKhaun -- 2013-09-24
//		Complete rewrite w/o recursion and now handles
//        escape codes within JSON text correctly
//    Version 1.2 -- 2013-07-10
//		Corrected mishandling of quoted numbers.
//		Corrected formatting of Key values in json objects.
//    Version 1.0 Released -- 2013-07-09
//
//    Usage: Place this stand-alone script within object containing program
//    you wish to debug and address it with
// llMessageLinked ( integer LINK_SET, integer MESSAGE_CHANNEL, string json, key NULL_KEY );
//	at the point(s) you wish to review the JSON string.
////////////////////////////////////////////////////

// Used as a "channel ID' for link messages
integer MESSAGE_CHANNEL = 75;

// helper function
chatThis (string output, integer lvl) {
	while (lvl--) output = "\t" + output;
	llOwnerSay (output);
}

prettyPrint( string jsonText ) {
	integer jLength = llStringLength( jsonText );
	string result = "";
	integer level = 0;
	integer iter = 0;
	string char;
	string prevChar;
	integer inQuote = FALSE;
	
	while (iter < jLength) {
		char = llGetSubString(jsonText, iter, iter++);
		if (char == "\"" && prevChar != "\\") { //"//
			inQuote = !inQuote;
			result += char;
		} else if (!inQuote) {
			if (char == "[" || char == "{" || char == ",") {
				chatThis(result + char, level);
				result = "";
				if (char != ",") ++level;
			} else if (char == "]" || char == "}") {
				if (result != "") chatThis(result, level);
				--level;
				result = char;
			} else if (char == ":") {
				result += ": ";
			} else {
				result += char;
			}
		} else {
			result += char;
		}
		prevChar = char;
	}
	chatThis(result, level);
}

// Main Program
default
{
	state_entry()
	{
		llOwnerSay ("Hello, " + llKey2Name(llGetOwner()));
		llOwnerSay ("Json Pretty Chat V2.0 awaits your JSON string");
		llOwnerSay ("Use " + (string)MESSAGE_CHANNEL + " for the second paramater of");
		llOwnerSay ("llMessageLinked\(\) and supply your JSON string in the third.");
	}
 
	link_message(integer sender_number, integer number, string message, key id)
	{
		if (number == MESSAGE_CHANNEL) {
			llOwnerSay("Pretty Chat of: " + message);
			prettyPrint(message);
		}
	}
}

Harness program, showing usage:

default
{
    state_entry()
    {
        llOwnerSay("Hello, Avatar!");
    }
 
    touch_start(integer total_number)
    {
        // Used as a "channel ID' for link messages
        integer MESSAGE_CHANNEL = 75;
 
        // http://www.codeproject.com/Articles/426142/JSON-Pretty-Print-and-JSON-Multi-level-Collapse-Co
        // From Heading: "Pretty Print" Code in JavaScript
        string source = 
"{\"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\"}}]}}";
 
        llMessageLinked (LINK_THIS, MESSAGE_CHANNEL, source, NULL_KEY);
    }
}

Outputs:

Object: Hello, LepreKhaun Resident
Object: Json Pretty Chat V2.0 is waiting for your JSON string
Object: Use 75 for the second paramater of
Object: llMessageLinked() and supply your JSON string in the third.

// Harness program checking in.
Object: Hello, Avatar!

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

== More Json Tips, Tricks and Coding Examples ==