Talk:Json usage in LSL

From Second Life Wiki
Jump to navigation Jump to search

I am concerned because the JSON format specifies at that you can use escape codes like \u0000 to represent Unicode byte values in strings. But LSL has the ugly habit of censoring and altering strings so that a character with byte value of 0x0000 is removed from the string, and some functions like llSHA1String are essentially broken since they also convert UTF-16 integers between \u0128–\u0255 into UTF-8 byte values starting with %c2 (which therefore have a different integer value due to the addition of the extraneous byte). Is LSL also going to mangle JSON strings' byte values when it renders them into LSL strings? Won't this corrupt attempts at efficiently verifying the signatures of any incoming messages, and thwart attempts to generate proper signatures for some outgoing JSON-formatted requests? Or do the Lindens have plans to finally give us a proper suite of escape codes in LSL (or some other solution)? --Gistya Eusebio 09:41, 30 May 2013 (PDT)

Add to that the complete crash-and-burn if your string starts with a quote, generating invalid JSON. I really don't get why LL finds it advantageous to include magic switches which forces everybody to do workaround for normal use, and ensures that all future JSON implementations in SL must be hand-coded to keep backwards compatibility with the spec breaks currently implemented. Tali Rosca 15:50, 19 June 2013 (PDT)

This sounds like a bug, you should report it. -- Strife (talk|contribs) 21:49, 20 June 2013 (PDT)
nm I see that you did. BUG-2594 -- Strife (talk|contribs) 21:50, 20 June 2013 (PDT)
I've been kicking and screaming about getting a robust JSON handling :-) 2594 got us some way, but we still have BUG-2736, which I consider so exceedingly ill-advised as to be a bug, despite the insistence that it's a really awesome feature. Tali Rosca 16:39, 21 June 2013 (PDT)
     The trailing quotation mark is the real nasty problem, not the leading one :D But yeah.. if they do add the capability to handle enquoted* text, how would that break anyone's scripts? Is anyone really relying on enquotation to invalidate their JSON strings on purpose? Besides when has breaking people's scripts stopped them from doing anything? I have tens of thousands of L$ worth of vehicles that are now worthless due to the Havok 4 update, but hey, life goes on. My copy of Microsoft Word 1.0 for Mac won't run on Mountain Lion either. I like backwards compatibility but we developers would be out of a job if software never had to be rewritten to work with the ever-evolving platforms that are out there :D
     --Gistya Eusebio 07:58, 23 June 2013 (PDT)
* I know "enquoted" is not in the dictionary. However it is in the lexicon. :D
A (somewhat kludgy) workaround for the mishandling of escaped characters can now be found here. Hope someone finds this useful.LepreKhaun Resident 23:41, 29 August 2013 (PDT)

I feel the paragraph within "Specifying Json Elements" that begins with "When JSON is presented in human-readable form,..." should be rewritten to show that the JSON string in its entirety is actually the root node of the structure, signified by an empty list used as "specifiers". LepreKhaun Resident 15:23, 6 July 2013 (PDT)

Unsure of major edit

After making the edit on 16:04, 15 August 2013 to correct code examples that wouldn't compile, I've come to realize that the given examples, as well as the surrounding text, is in error since json disallows empty values, as one might find in a "sparse" array.

The author is pointing out "a rare exception" but then uses "{\"parent\":,}" and "{\"parent\":[ , , , , ]}" to illustrate. Neither of those can be arrived at with llList2Json(), since LSL doesn't allow empty list elements, but can only be obtained by hand coding to arrive at the non-compliant json strings.

I feel that whole section should be rewritten to simply point out to the reader that they are advised to use llList2Json() in the formation of json strings and avoid hand coding, which may well result in mal-formed constructions that could lead to confusing results in later operations.

However, doing so would excise a number of paragraphs and I'm unsure how that would set with the original author and others. Guidance on this would be appreciated. LepreKhaun Resident 05:25, 18 August 2013 (PDT)

JSON example

I want to submit a simple, working example on LSL JSON, but I don't know the right place for it

I hope Strife will and can place it, here it is:

<lsl> // JSON array forum example by Dora Gustafson, Studio Dora 2013 // Building an 3 by 5 array in a JSON Object // Rows are indexed by name and columns are indexed by number = 0,1,2,3,4

string JSONVotes;

tellVotes( string voter) {

   string Js = llJsonGetValue( JSONVotes, [voter]);
   list Jl = llParseString2List( Js,[",","[","]","\""],[]);
   string output = llDumpList2String( Jl, ", ");
   llOwnerSay( "Votes from "+voter+" are: "+output);


default {

   {   // Building the JSON object
       string votes = llList2Json( JSON_ARRAY, [0, 0, 0, 0, 0]); // one row
       JSONVotes = llList2Json( JSON_OBJECT, [ "Betty", votes, "Jerry", votes, "Pierre", votes]); // complete object
   touch_end( integer num)
   {   // Testing the JSON object
       tellVotes( "Betty");
       tellVotes( "Jerry");
       tellVotes( "Pierre");
       // saving some random votes
       JSONVotes = llJsonSetValue( JSONVotes, ["Betty", 1], (string)llFrand( 100.0));
       JSONVotes = llJsonSetValue( JSONVotes, ["Jerry", 4], (string)llFrand( 100.0));
       // testing
       tellVotes( "Betty");
       tellVotes( "Jerry");
       tellVotes( "Pierre");
       // getting one vote, example
       string s = llJsonGetValue( JSONVotes, ["Betty",1]);
       llOwnerSay( "Betty votes "+s+" in second column");

}</lsl>Dora Gustafson 06:23, 25 August 2013 (PDT)

Inconsistent behavior on types

The documentation says: if the specifier list element is an integer, then the corresponding element in the json value must be an array and the list element is used as a zero-based index into the Json array.

However, placing integers in a specifier used with a JSON_OBJECT and llJsonGetValue, they are automatically converted to strings. llList2Json and llJsonSetValue do not automatically convert integers to strings. Both will result in a JSON_INVALID if you try to put integers on the key side of a JSON_OBJECT.

This example code, according to the documentation shouldn't even work (I'd presume it's supposed to return a JSON_INVALID):

<lsl>string test = llList2Json(JSON_OBJECT, ["1", "one", "2", "two", "3", "three"]); llOwnerSay(llJsonGetValue(test, [3]));</lsl>

This little sniplet produces "three". Additionally, using llJsonValueType in place of llJsonGetValue in the above example will result in JSON_STRING. Attempting something like 'llJsonSetValue(test, [3], "three");' results in JSON_INVALID.

Chetar Ruby 09:15, 14 October 2013 (PDT)

Yes, that's because what you meant to say was llJsonSetValue(test, ["3"], "three")– objects in LSL JSON land are always keyed on STRINGS– you can't pass numbers even when the string looks like a number. -- Winter Seale 12:35, 23 January 2014 (PST)
Right, but you're overlooking what was being pointed out, a string isn't being required using llJsonGetValue() on a JSON object. It's an anomaly, though I can't see how this might adversely affect anything. LepreKhaun Resident 14:29, 24 January 2014 (PST)

Major change to the last part

I've made a major change per; the change is - can someone please review it for accuracy? --Sei Lisa 18:09, 6 June 2014 (PDT)

Review is not the same as undo. I expected some commentary on my edit, not a full reversal. Why is there an example using undocumented features, and why has the explanatory text that goes with the example been removed? --Sei Lisa 11:21, 9 June 2014 (PDT)
I'm reverting Miranda's changes for several reasons.
1) The justification for the removal of the paragraph is redundancy. Nowhere in the article explains how the strings are interpreted when they aren't quoted inside the string itself (like the LSL string "\"true\""). The text merely says: "LSL strings which both begin and end with "\"" are interpreted literally as JSON strings, while those without are parsed when converted into JSON." But it does not explain what it means by parsed. It's very ambiguous, and it's not clear at all from that how it acts. The addition of a text that explains how the strings "true", "false" and "null" behave is therefore NOT redundant.
2) There's no example of how to properly encode strings. Having an example that omits the quotes around the string values may lead to think that that's the norm, when that is undocumented behavior (nowhere in the article says what llList2Json or llJsonSetValue actually do with strings that don't decode to any valid JSON type - they happen to be translated to JSON strings, but some of these strings like "true", "false", "[]", etc. will not, and that's not exaplained).
3) The paragraph was added in this edit: - note how the example, initially written by Maestro, was buggy to the point that it used TRUE instead of JSON_TRUE, therefore the explanatory text was not redundant. It was merely not totally accurate, and I believe my edits made it clearer.
--Sei Lisa 11:58, 9 June 2014 (PDT)

Text incorrect

This section looks factually incorrect:

If, anywhere along the line, any of the specified nodes do not exist, llJsonGetValue and llJsonValueType will almost always return JSON_INVALID. However there is a rare exception: if any specifier in the list leads to a node that has no characters in its JSON string value, JSON_NULL will be returned instead of JSON_INVALID—no matter what might come after it in the specifiers list. For example in:

<lsl> string example = "{\"parent\":,}"; string test1 = llJsonGetValue(example,["parent"]); string test2 = llJsonGetValue(example,["parent","child that doesn't exist","etc."]); </lsl> test1 and test2 will both be JSON_NULL.

The same is true for arrays: a specifier pointing to any element of a valid array will return JSON_NULL anywhere there is no JSON value specified at given position in the array:

<lsl> string example = "{\"parent\":[ , , , , ]}"; string test1 = llJsonGetValue(example,["parent",2]); string test2 = llJsonGetValue(example,["parent",1,"child that does not exist","etc."]); </lsl> test1 and test2 will also both be JSON_NULL.

These types of scenarios may be useful in determining valid JSON paths for the setter: in all the scenarios where JSON_NULL is returned, the same set of specifiers is able to be successfully used for llJsonSetValue. However if JSON_INVALID is returned, there is no guarantee the setter won't return an error.

When I run this script: <lsl> default {

       string example = "{\"parent\":[ , ,  , , ]}";
       string test1 = llJsonGetValue(example,["parent",2]);
       string test2 = llJsonGetValue(example,["parent",1,"child that does not exist","etc."]);
       example = "{\"parent\":,}"; 
       test1 = llJsonGetValue(example,["parent"]);
       test2 = llJsonGetValue(example,["parent","child that doesn't exist","etc."]);

} </lsl> I get:

[07:58:42] Object: %EF%B7%90
[07:58:42] Object: %EF%B7%90
[07:58:42] Object: %EF%B7%90
[07:58:42] Object: %EF%B7%90

that is, JSON_INVALID four times, I wonder if it's a change of mind or a bug. However, given the attention (or lack thereof) I've received in my bug report in I'm unsure if reporting it as a bug is a good idea. Maybe that section should just be removed? --Sei Lisa 08:07, 2 July 2014 (PDT)

Performance issues

I did some performance testing, comparing the use of string, list, and Json functions. Detailed results are on my page (click my name below), but the summary is:

  • List searching and extraction is MUCH faster than llJsonGetValue (well over an order of magnitude)
  • Creating JSON strings by hand or through string concatenation is FAR more efficient than using llList2Json.
  • For extracting multiple values from a JSON object, it's substantially faster (but probably not an order of magnitude faster) to use llJson2List once, then extract data from the list.
  • The LSL string manipulation functions (llSubStringIndex, llGetSubString, llDeleteSubString, llInsertString) are individually slower than JSON functions, but for performing any full operation on a JSON string (i.e. search for an old value, replace it with a new one), the JSON functions almost certainly are more efficient.
  • Compared with using lists, using JSON strings is a lot slower. However, it may be more efficient in memory usage, and certainly can make for much more readable code and data, and this may be sufficient to offset the performance penalty.
  • When using list functions, let LSL convert a string to a one-element list automatically (list2 += "a" beats list2 += ["a"])
  • llList2Integer(...) is faster than (integer)llList2String(...)

I hope the new virtual world LL recently announced it's working on will have a scripting language that supports real object datatypes... hope hope... Brattle Resident 06:09, 11 July 2014 (PDT)