Difference between revisions of "User:LepreKhaun Resident/Json Pretty Printer"

From Second Life Wiki
Jump to: navigation, search
(Version 2.0, major rewrite and way mo' bettah. :))
Line 14: Line 14:
 
//
 
//
 
//    A debugging tool for Json construction
 
//    A debugging tool for Json construction
//    Version 1.2 by LepreKhaun -- 2013-07-10
+
//    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 mishandling of quoted numbers.
 
// Corrected formatting of Key values in json objects.
 
// Corrected formatting of Key values in json objects.
Line 28: Line 31:
 
integer MESSAGE_CHANNEL = 75;
 
integer MESSAGE_CHANNEL = 75;
  
// How deep we are in the json structure
+
// helper function
integer LEVEL = 0;
+
chatThis (string output, integer lvl) {
+
while (lvl--) output = "\t" + output;
// User functions
+
llOwnerSay (output);
chatThis (string message) {
+
string indent = "";
+
integer iter = LEVEL;
+
 
+
while (iter--){
+
indent += "\t";
+
}
+
llOwnerSay (indent + message);
+
 
}
 
}
  
handleValue (string prePend, string value, string apPend) {
+
prettyPrint( string jsonText ) {
// JSON Value Type
+
integer jLength = llStringLength( jsonText );
string valueType = llJsonValueType(value, []);
+
string result = "";
+
integer level = 0;
if (valueType == JSON_FALSE) {
+
chatThis (prePend + "false" + apPend);
+
} else if (valueType == JSON_TRUE) {
+
chatThis (prePend + "true" + apPend);
+
} else if (valueType == JSON_NULL) {
+
chatThis (prePend + "null" + apPend);
+
} else if (valueType == JSON_NUMBER) {
+
chatThis (prePend + value + apPend);
+
} else if (valueType == JSON_ARRAY) {
+
chatThis (prePend + "[");
+
++LEVEL;
+
handleJsonArray (value);
+
--LEVEL;
+
chatThis ("]" + apPend);
+
} else if (valueType == JSON_OBJECT) {
+
chatThis (prePend + "{");
+
++LEVEL;
+
handleJsonObject (value);
+
--LEVEL;
+
chatThis ("}" + apPend);
+
// NOTE: Once back in list form, all strings evaluate to JSON_INVALID
+
// because of having their enclosing double quotes (") stripped, So...
+
} else {
+
// We'll treat it as a String
+
chatThis (prePend + value + apPend);
+
}
+
}
+
 
+
handleJsonArray (string jsonArray) {
+
list valueList = llJson2List(jsonArray);
+
 
integer iter = 0;
 
integer iter = 0;
integer listLength = llGetListLength(valueList);
+
string char;
 +
string prevChar;
 +
integer inQuote = FALSE;
 
 
while (iter<listLength) {
+
while (iter < jLength) {
string value = llList2String(valueList, iter);
+
char = llGetSubString(jsonText, iter, iter++);
if (llJsonValueType(jsonArray,[iter])== JSON_STRING) value = "\"" + value + "\"";
+
if (char == "\"" && prevChar != "\\") {
if (++iter == listLength) handleValue ("", value, "");
+
inQuote = !inQuote;
else handleValue ("", value, ",");
+
result += char;
}
+
} else if (!inQuote) {
}
+
if (char == "[" || char == "{" || char == ",") {
 
+
chatThis(result + char, level);
handleJsonObject (string jsonObject) {
+
result = "";
list valueList = llJson2List(jsonObject);
+
if (char != ",") ++level;
integer iter = 0;
+
} else if (char == "]" || char == "}") {
integer listLength = llGetListLength(valueList);
+
if (result != "") chatThis(result, level);
while (iter<listLength) {
+
--level;
string myKey = llList2String(valueList, iter);
+
result = char;
string value = llList2String(valueList, ++iter);
+
} else if (char == ":") {
if (llJsonValueType(jsonObject,[myKey])== JSON_STRING) value = "\"" + value + "\"";
+
result += ": ";
myKey = "\"" + myKey + "\": ";
+
} else {
 
+
result += char;
if (++iter == listLength) handleValue (myKey, value, "");
+
}
else handleValue (myKey, value, ",");
+
} else {
 +
result += char;
 +
}
 +
prevChar = char;
 
}
 
}
 +
chatThis(result, level);
 
}
 
}
  
Line 108: Line 79:
 
{
 
{
 
llOwnerSay ("Hello, " + llKey2Name(llGetOwner()));
 
llOwnerSay ("Hello, " + llKey2Name(llGetOwner()));
llOwnerSay ("Json Pretty Chat awaits your JSON string");
+
llOwnerSay ("Json Pretty Chat V2.0 awaits your JSON string");
 
llOwnerSay ("Use " + (string)MESSAGE_CHANNEL + " for the second paramater of");
 
llOwnerSay ("Use " + (string)MESSAGE_CHANNEL + " for the second paramater of");
 
llOwnerSay ("llMessageLinked\(\) and supply your JSON string in the third.");
 
llOwnerSay ("llMessageLinked\(\) and supply your JSON string in the third.");
 
}
 
}
+
 
link_message(integer sender_number, integer number, string message, key id)
 
link_message(integer sender_number, integer number, string message, key id)
 
{
 
{
 
if (number == MESSAGE_CHANNEL) {
 
if (number == MESSAGE_CHANNEL) {
 
llOwnerSay("Pretty Chat of: " + message);
 
llOwnerSay("Pretty Chat of: " + message);
handleValue("", message, "");
+
prettyPrint(message);
 
}
 
}
 
}
 
}
Line 124: Line 95:
  
 
Harness program, showing usage:
 
Harness program, showing usage:
 +
 
<lsl>
 
<lsl>
 
default
 
default
Line 131: Line 103:
 
         llOwnerSay("Hello, Avatar!");
 
         llOwnerSay("Hello, Avatar!");
 
     }
 
     }
 
+
 
     touch_start(integer total_number)
 
     touch_start(integer total_number)
 
     {
 
     {
 
         // Used as a "channel ID' for link messages
 
         // Used as a "channel ID' for link messages
 
         integer MESSAGE_CHANNEL = 75;
 
         integer MESSAGE_CHANNEL = 75;
 
+
         string source = llList2Json(JSON_OBJECT, ["x",llList2Json(JSON_ARRAY, ["x", 1, JSON_TRUE]),"Y",JSON_FALSE]);
+
        // 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);
 
         llMessageLinked (LINK_THIS, MESSAGE_CHANNEL, source, NULL_KEY);
 
     }
 
     }
Line 147: Line 137:
 
<pre>
 
<pre>
 
Object: Hello, LepreKhaun Resident
 
Object: Hello, LepreKhaun Resident
Object: Json Pretty Chat is waiting for your JSON string
+
Object: Json Pretty Chat V2.0 is waiting for your JSON string
 
Object: Use 75 for the second paramater of
 
Object: Use 75 for the second paramater of
 
Object: llMessageLinked() and supply your JSON string in the third.
 
Object: llMessageLinked() and supply your JSON string in the third.
Line 155: Line 145:
  
 
// Result of touch_start()
 
// Result of touch_start()
Object: Pretty Chat of: {"x":["x",1,true],"Y":false}
 
 
Object: {
 
Object: {
Object:    "x": [
+
Object:    "apiVersion": "2.0",
Object:        "x",
+
Object:    "data": {
Object:        1,
+
Object:        "updated": "2010-01-07T19:58:42.949Z",
Object:        true
+
Object:        "totalItems": 800,
Object:     ],
+
Object:        "startIndex": 1,
Object:     "Y": false
+
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: }
 
Object: }
 
</pre>
 
</pre>

Revision as of 07:07, 24 September 2013

[NOTE: Since I refrain from rearranging the flamingos in front of your trailer home, you are expected to extend the courtesy and leave comments, suggested improvements, corrections of fact or your own personal preferences 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.

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.

<lsl> //////////////////////////////////////////////////// // 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); } } } </lsl>

Harness program, showing usage:

<lsl> 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);
   }

} </lsl>

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 ==