Innula Zenovka Posted January 7, 2023 Share Posted January 7, 2023 I've never really looked at json before, but now I find I have to as part of my adventures with shared media -- essentially, I'm receiving data from a remote server in the form of json objects and I need, in the http_response event, to extract the contents of particular fields and then format them as entries in an HTML table I display on the prim. How, using this example from https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/JSON, would I pull out the contents of the "name" and "powers" fields for each superhero in the list? { "squadName": "Super hero squad", "homeTown": "Metro City", "formed": 2016, "secretBase": "Super tower", "active": true, "members": [ { "name": "Molecule Man", "age": 29, "secretIdentity": "Dan Jukes", "powers": ["Radiation resistance", "Turning tiny", "Radiation blast"] }, { "name": "Madame Uppercut", "age": 39, "secretIdentity": "Jane Wilson", "powers": [ "Million tonne punch", "Damage resistance", "Superhuman reflexes" ] }, { "name": "Eternal Flame", "age": 1000000, "secretIdentity": "Unknown", "powers": [ "Immortality", "Heat Immunity", "Inferno", "Teleportation", "Interdimensional travel" ] } ] } 1 Link to comment Share on other sites More sharing options...
Love Zhaoying Posted January 7, 2023 Share Posted January 7, 2023 (edited) Ok, I'm using JSON for "everything" now, so will give it a shot! Edited January 7, 2023 by Love Zhaoying 1 Link to comment Share on other sites More sharing options...
Love Zhaoying Posted January 7, 2023 Share Posted January 7, 2023 (edited) string sJson = "{\"squadName\":\"Super hero squad\",\"homeTown\":\"Metro City\",\"formed\":2016,\"secretBase\":\"Super tower\",\"active\":true,\"members\":[{\"name\":\"Molecule Man\",\"age\":29,\"secretIdentity\":\"Dan Jukes\",\"powers\":[\"Radiation resistance\",\"Turning tiny\",\"Radiation blast\"]},{\"name\":\"Madame Uppercut\",\"age\":39,\"secretIdentity\":\"Jane Wilson\",\"powers\":[\"Million tonne punch\",\"Damage resistance\",\"Superhuman reflexes\"]},{\"name\":\"Eternal Flame\",\"age\":1000000,\"secretIdentity\":\"Unknown\",\"powers\":[\"Immortality\",\"Heat Immunity\",\"Inferno\",\"Teleportation\",\"Interdimensional travel\"]}]}"; default { state_entry() { integer iMember; string sMemberJson; iMember = 0; sMemberJson = llJsonGetValue(sJson, ["members", iMember]); // Get first Entry while (sMemberJson != JSON_INVALID) { llOwnerSay("Member Name: " + llJsonGetValue(sMemberJson, ["name"])); ++iMember; sMemberJson = llJsonGetValue(sJson, ["members", iMember]); // Get next Entry } } } Output: Member Name: Molecule Man Member Name: Madame Uppercut Member Name: Eternal Flame Thanks for giving me something to do!!! *edit* You could also do it with just a single llJsonGetValue() call, duplicated before and inside the loop like this (assuming you only needed the "name" field): sMemberName = llJsonGetValue(sJson, ["members", iMember, "name"]); // Get first Entry / next Entry The previous example becomes: default { state_entry() { integer iMember; string sMemberName; iMember = 0; sMemberName = llJsonGetValue(sJson, ["members", iMember, "name"]); while (sMemberName != JSON_INVALID) { llOwnerSay("Member Name: " +sMemberName); ++iMember; sMemberName = llJsonGetValue(sJson, ["members", iMember, "name"]); } } } Edited January 7, 2023 by Love Zhaoying Fixed the second comment 1 1 Link to comment Share on other sites More sharing options...
Innula Zenovka Posted January 7, 2023 Author Share Posted January 7, 2023 (edited) Thanks! Presumably if I add the names to a "names" list and then do the same thing with the "powers" field, and, at least in theory, I should end up with two synchronised LSL lists, "names" and "powers"? Another question: the JSON I'm working with has several embedded arrays (I think that's the correct term). For example, it contains a number of entries for a field called simply "items", each of which contains fields like "id", "name"", "artist", "album" and so on, but also an array inside the items field for "genres", which also contains multiple items for "id" and "name". How do I reference these for llJsonGetValues? Presumably I use llJsonGetValue("items",iItem,""album") for the names of the albums. How do I reference the "name" field in genres, bearing in mind a single album may belong to more than one genre? I'm wanting to use something like "items.genres" or "genres.name" but I'm not all sure of what I'm doing here. Edited January 7, 2023 by Innula Zenovka Link to comment Share on other sites More sharing options...
Xiija Posted January 7, 2023 Share Posted January 7, 2023 (edited) @Innula Zenovka if your data is unchanging, you could cherry pick the info you need mebbe? ( from your prev example ) in your http response event, you could do ... string firstArray = llJsonGetValue(body,["members", 0, "powers"]); llOwnerSay("data: \n" + firstArray ); // returns ["Radiation resistance","Turning tiny","Radiation blast"] Edited January 7, 2023 by Xiija 1 Link to comment Share on other sites More sharing options...
Love Zhaoying Posted January 7, 2023 Share Posted January 7, 2023 (edited) 55 minutes ago, Innula Zenovka said: Thanks! Presumably if I add the names to a "names" list and then do the same thing with the "powers" field, and, at least in theory, I should end up with two synchronised LSL lists, "names" and "powers"? Yes. Personally, I stopped using lists COMPLETELY. So, if I really only needed to "mine" the names and powers, I'd just create a new JSON with just the data I needed. Example using JSON_ARRAYS with a single JSON_OBJECT in each array element: { // Outer JSON_OBJECT [ // JSON_ARRAY {"name":"name1", "power":"power1"}, // JSON_ARRAY entry 1 is a JSON_OBJECT {"name":"name2", "power":"power2"}, // JSON_ARRAY entry 2 is a JSON_OBJECT ] } ..Lists within Lists..! 55 minutes ago, Innula Zenovka said: Another question: the JSON I'm working with has several embedded arrays (I think that's the correct term). For example, it contains a number of entries for a field called simply "items", each of which contains fields like "id", "name"", "artist", "album" and so on, but also an array inside the items field for "genres", which also contains multiple items for "id" and "name". How do I reference these for llJsonGetValues? Presumably I use llJsonGetValue("items",iItem,""album") for the names of the albums. How do I reference the "name" field in genres, bearing in mind a single album may belong to more than one genre? I'm wanting to use something like "items.genres" or "genres.name" but I'm not all sure of what I'm doing here. Perhaps if you showed me an example. The key to it all is the second parameter on llJsonGetValue() - I call it "[specifiers]" - a list of specifiers for what you want to access in the list. Is it for example: Artists, Albums, Album Details? { // Outer JSON_OBJECT [ // Array of Artists { "Artist": "Artist 1", // JSON_OBJECT for Artist 1 "Albums": [ // Array of Albums for Artist 1 { "name": "Album1", id": 123, "year": 1974 }, { "name": "Album2", id": 345, "year": 1983 } ] // End of Albums for Artist 1 }, // End of JSON_OBJECT for Artist 1 { "Artist": "Artist 2", // JSON_OBJECT for Artist 2 "Albums": [ // Array of Albums for Artist 2 { "name": "Album3", id": 789, "year": 1999}, { "name": "Album4", id": 135,"year": 2000} ] // End of Albums for Artist 2 } // End of JSON_OBJECT for Artist 2 ] // end of Artists Array } Edited January 7, 2023 by Love Zhaoying Removed comma Link to comment Share on other sites More sharing options...
Love Zhaoying Posted January 7, 2023 Share Posted January 7, 2023 (edited) @Innula Zenovka, sorry the last example took so long! I hope this is along the lines of your data, for matching your use-case. Example with the above: string sJson = "[{\"Artist\":\"Artist 1\",\"Albums\":[{\"name\":\"Album1\",\"id\":123,\"year\":1974},{\"name\":\"Album2\",\"id\":345,\"year\":1983}]},{\"Artist\":\"Artist 2\",\"Albums\":[{\"name\":\"Album3\",\"id\":789,\"year\":1999},{\"name\":\"Album4\",\"id\":135,\"year\":2000}]}]"; default { state_entry() { integer iArtist; string sArtistName; iArtist = 0; sArtistName = llJsonGetValue(sJson, [iArtist, "Artist"]); // Get first Artist while (sArtistName != JSON_INVALID) { llOwnerSay("Artist: " + sArtistName); integer iAlbum; string sAlbumJson; string sAlbumName; integer iAlbumYear; string sAlbumID; iAlbum = 0; sAlbumJson = llJsonGetValue(sJson, [iArtist, "Albums", iAlbum]); // Get first Album while (sAlbumJson!=JSON_INVALID) { sAlbumName = llJsonGetValue(sAlbumJson, ["name"]); iAlbumYear = (integer)llJsonGetValue(sAlbumJson, ["year"]); sAlbumID = llJsonGetValue(sAlbumJson, ["id"]); llOwnerSay("Album " + (string)(iAlbum+1) + ": name = " + sAlbumName + ", year = " + (string)iAlbumYear + " ID = " + sAlbumID); ++iAlbum; sAlbumJson = llJsonGetValue(sJson, [iArtist, "Albums", iAlbum]); // Get next Album } ++iArtist; sArtistName = llJsonGetValue(sJson, [iArtist, "Artist"]); // Get next Album } } } Output: Artist: Artist 1 Album 1: name = Album1, year = 1974 ID = 123 Album 2: name = Album2, year = 1983 ID = 345 Artist: Artist 2 Album 1: name = Album3, year = 1999 ID = 789 Album 2: name = Album4, year = 2000 ID = 135 Edited January 7, 2023 by Love Zhaoying 1 Link to comment Share on other sites More sharing options...
Love Zhaoying Posted January 7, 2023 Share Posted January 7, 2023 Here is what is in the JSON_OBJECT in the above example: [ { "Artist": "Artist 1", "Albums": [ { "name": "Album1", "id": 123, "year": 1974 }, { "name": "Album2", "id": 345, "year": 1983 } ] }, { "Artist": "Artist 2", "Albums": [ { "name": "Album3", "id": 789, "year": 1999 }, { "name": "Album4", "id": 135, "year": 2000 } ] } ] 1 Link to comment Share on other sites More sharing options...
Innula Zenovka Posted January 7, 2023 Author Share Posted January 7, 2023 27 minutes ago, Love Zhaoying said: Perhaps if you showed me an example. Sure. This has only one item, but there could be several. { {"itemsCount":1, "pagesCount":1, "items":[ {"id":"a uuid", "name":"name of track", "artist":"name of artist", "album":"name of album", "duration":"playing time", "genres":[ {"id":12, "name":"Soul/R&B"}], "image":{"preview":"url of album cover"}, "price":n, "currency": {"id":4,"name":"name of currency", "imageUrl":"url for currency symbol"}, "status":"PURCHASED", "isNew":true, "isPreviewAvailable":true} ]} } So I want, for example, to reference each name in items and, along with that, each name in genres for that item. Link to comment Share on other sites More sharing options...
Love Zhaoying Posted January 7, 2023 Share Posted January 7, 2023 (edited) 25 minutes ago, Innula Zenovka said: So I want, for example, to reference each name in items and, along with that, each name in genres for that item. I had to make one change to your example JSON, put quotes around the "n" for "price". Note: Loops would go after each place where I set "variable = 0". string sJson = "{\"itemsCount\":1,\"pagesCount\":1,\"items\":[{\"id\":\"a uuid\",\"name\":\"name of track\",\"artist\":\"name of artist\",\"album\":\"name of album\",\"duration\":\"playing time\",\"genres\":[{\"id\":12,\"name\":\"Soul/R&B\"}],\"image\":{\"preview\":\"url of album cover\"},\"price\":\"n\",\"currency\":{\"id\":4,\"name\":\"name of currency\",\"imageUrl\":\"url for currency symbol\"},\"status\":\"PURCHASED\",\"isNew\":true,\"isPreviewAvailable\":true}]}"; default { state_entry() { integer iItem = 0; llOwnerSay("For iItem = " + (string)iItem + ":"); string sName; sName = llJsonGetValue(sJson, ["items", iItem, "name"]); integer iGenre = 0; llOwnerSay("For iGenre = " + (string)iGenre + ":"); string sGenre; sGenre = llJsonGetValue(sJson, ["items", iItem, "genres", iGenre, "name"]); llOwnerSay("Name = " + sName + ", Genre = " + sGenre); } } Edited January 7, 2023 by Love Zhaoying Oops, replaced one "0" with iGenre 1 Link to comment Share on other sites More sharing options...
Quistess Alpha Posted January 7, 2023 Share Posted January 7, 2023 42 minutes ago, Innula Zenovka said: { {"itemsCount":1, "pagesCount":1, "items":[ {"id":"a uuid", "name":"name of track", "artist":"name of artist", "album":"name of album", "duration":"playing time", "genres":[ {"id":12, "name":"Soul/R&B"}], "image":{"preview":"url of album cover"}, "price":n, "currency": {"id":4,"name":"name of currency", "imageUrl":"url for currency symbol"}, "status":"PURCHASED", "isNew":true, "isPreviewAvailable":true} ]} } This specifically seems to be invalid JSON, if you're getting something like this from your server, you'll need to remove the outermost set of curly braces. Cleaning up the formatting of the JSON a little to make it clearer and adding more than one element per array might make things clearer. maybe stepping through the JSON one level at a time might make things clearer before trying to write a general routine? string JSON = "{ \"itemsCount\":1, \"pagesCount\":1, \"items\": [ { \"id\":\"a uuid\", \"name\":\"name of track\", \"artist\":\"name of artist\", \"album\":\"name of album\", \"duration\":\"playing time\", \"genres\": [ { \"id\":12, \"name\":\"Soul/R&B\" }, { \"id\":13, \"name\":\"Funk\" }, ], \"image\": { \"preview\":\"url of album cover\" }, \"price\":n, \"currency\": { \"id\":4,\"name\":\"name of currency\", \"imageUrl\":\"url for currency symbol\" }, \"status\":\"PURCHASED\", \"isNew\":true, \"isPreviewAvailable\":true }, { \"id\":\"another uuid\", \"name\":\"name of a different track\", \"artist\":\"name of other artist\", \"album\":\"name of different album\", \"duration\":\"playing time\", \"genres\": [ { \"id\":12, \"name\":\"Soul/R&B\" }, { \"id\":13, \"name\":\"Funk\" }, ], \"image\": { \"preview\":\"url of album cover\" }, \"price\":n, \"currency\": { \"id\":4, \"name\":\"name of currency\", \"imageUrl\":\"url for currency symbol\" }, \"status\":\"PURCHASED\", \"isNew\":true, \"isPreviewAvailable\":true } ] } "; string json_type2string(string s) { if(s==JSON_OBJECT) { return "JSON_OBJECT"; }else if(s==JSON_ARRAY) { return "JSON_ARRAY"; }else if(s==JSON_NUMBER) { return "JSON_NUMBER"; }else if(s==JSON_STRING) { return "JSON_STRING"; }else if(s==JSON_NULL) { return "JSON_NULL"; }else if(s==JSON_TRUE) { return "JSON_TRUE"; }else if(s==JSON_FALSE) { return "JSON_FALSE"; }else if(s==JSON_DELETE) { return "JSON_DELETE"; } return "JSON_INVALID"; } default { state_entry() { llOwnerSay(llJsonGetValue(JSON,["items"])); // returns a JSON_ARRAY. (surrounded by '[]') llOwnerSay(json_type2string(llJsonValueType(JSON,["items"]))); llOwnerSay("\n----\n"); llOwnerSay(llJsonGetValue(JSON,["items",0])); // the 0th element of the array. is a JSON_OBJECT (surrounded by '{}') llOwnerSay(json_type2string(llJsonValueType(JSON,["items",0]))); llOwnerSay("\n----\n"); llOwnerSay(llJsonGetValue(JSON,["items",0,"genres"])); // returns another JSON_ARRAY. llOwnerSay(json_type2string(llJsonValueType(JSON,["items",0,"genres"]))); llOwnerSay("\n----\n"); llOwnerSay(llJsonGetValue(JSON,["items",0,"genres",0])); // returns a JSON_OBJECT llOwnerSay(json_type2string(llJsonValueType(JSON,["items",0,"genres",0]))); llOwnerSay("\n----\n"); llOwnerSay(llJsonGetValue(JSON,["items",0,"genres",0,"name"])); // returns a string: Soul/R&B llOwnerSay(json_type2string(llJsonValueType(JSON,["items",0,"genres",0,"name"]))); llOwnerSay("\n---\n"); llOwnerSay(llJsonGetValue(JSON,["items",0,"genres",1,"name"])); // returns a string: Funk llOwnerSay(json_type2string(llJsonValueType(JSON,["items",0,"genres",1,"name"]))); llOwnerSay("\n---\n"); llOwnerSay(llJsonGetValue(JSON,["items",0,"genres",2,"name"])); // returns JSON_INVALID (because past end of Array) llOwnerSay(json_type2string(llJsonValueType(JSON,["items",0,"genres",2,"name"]))); llOwnerSay("\n---\n"); } } Big idea, for a JSON_OBJECT, you get something inside by asking for one of the keys of a key-vlaue pair (I'm not actually sure how you would get the keys to ask for without knowing something about the format of the JSON a-priori, or converting the JSON_OBJECT to a strided list with llJson2List). for a JSON_ARRAY you get something inside by asking for an index, and to iterate, you ask for indexes starting at 0 and stopping when you get JSON_INVALID as an answer. 1 Link to comment Share on other sites More sharing options...
Love Zhaoying Posted January 7, 2023 Share Posted January 7, 2023 2 minutes ago, Quistess Alpha said: This specifically seems to be invalid JSON, if you're getting something like this from your server, you'll need to remove the outermost set of curly braces. JsonEditorOnline was not my friend with that last example. Think I had to remove the outer {} AND change an n to a "n". 1 Link to comment Share on other sites More sharing options...
Love Zhaoying Posted January 7, 2023 Share Posted January 7, 2023 4 minutes ago, Quistess Alpha said: for a JSON_ARRAY you get something inside by asking for an index, and to iterate, you ask for indexes starting at 0 and stopping when you get JSON_INVALID as an answer. It's such a shame you can't get a count directly for arrays, and have to iterate (or convert the array to a list) to get the count. Otherwise, the Object / Array combination works well for me! 1 Link to comment Share on other sites More sharing options...
Quistess Alpha Posted January 7, 2023 Share Posted January 7, 2023 1 minute ago, Love Zhaoying said: It's such a shame you can't get a count directly for arrays, and have to iterate (or convert the array to a list) to get the count. If I'm understanding this example correctly, I think "itemsCount" was intended to be the length of the array contained in items, but yeah, a shame. If you ~really just needed the length of the array without iterating, for a sufficiently large array it might be possible to play hot and cold to get the length more efficiently (I.E. is there an element at position 1? yes -> 2? yes-> 4?yes ->8? yes-> 16? -> no 12? no -> 10? yes -> 11? yes -> list has 11 elements (8 checks) ) 1 Link to comment Share on other sites More sharing options...
Love Zhaoying Posted January 7, 2023 Share Posted January 7, 2023 28 minutes ago, Quistess Alpha said: f you ~really just needed the length of the array without iterating, for a sufficiently large array it might be possible to play hot and cold to get the length more efficiently (I.E. is there an element at position 1? yes -> 2? yes-> 4?yes ->8? yes-> 16? -> no 12? no -> 10? yes -> 11? yes -> list has 11 elements (8 checks) ) By total coincidence, my current "proof of concept" for the big JSON project is a "number guessing game". I am going to train the program to also be a "guesser", and it seems that a combination of using "prime numbers" plus the "divide by 2 and pick a side closer/farther randomly" works best for human guessing. 1 Link to comment Share on other sites More sharing options...
Xiija Posted January 7, 2023 Share Posted January 7, 2023 (edited) @Innula Zenovka Quote How do I reference the "name" field in genres made a quickie json sender with your info for testing ... https://replit.com/@TikiHed/SL-json-responder#index.js JSON sender ( the JSON ) you can make an http request to .. "https://SL-json-responder.tikihed.repl.co/input" . I changed the JSON a bit, not sure if you are pulling json from somewhere or you are making it, but the 'music.json' file in the node.js repl (above) has the format i used. with that, i could do... string jdata = llJsonGetValue( body, ["items", "genres", 0, "name" ]); llOwnerSay("data: \n" + jdata ); Edited January 7, 2023 by Xiija 1 Link to comment Share on other sites More sharing options...
Innula Zenovka Posted January 8, 2023 Author Share Posted January 8, 2023 Thanks, everyone! This is a huge help, and I'm beginning to understand what I'm doing with JSON, at least in this case. Another question, though. In the example I'm using, what I've got for "image" is "image":{ "preview":"some url", "origin":"another url" }, That is, it's a JSON object inside the "item" object, containing two values, and that's how Quistess' example recognises it. How do I reference the values inside this embedded object for "preview" and "origin" respectively? Link to comment Share on other sites More sharing options...
Love Zhaoying Posted January 8, 2023 Share Posted January 8, 2023 26 minutes ago, Innula Zenovka said: Thanks, everyone! This is a huge help, and I'm beginning to understand what I'm doing with JSON, at least in this case. Another question, though. In the example I'm using, what I've got for "image" is "image":{ "preview":"some url", "origin":"another url" }, That is, it's a JSON object inside the "item" object, containing two values, and that's how Quistess' example recognises it. How do I reference the values inside this embedded object for "preview" and "origin" respectively? Just add image, preview or image, origin to the [specfiers] list parameter you'd pass to llJsonGetValue for any "higher level" fields in the same JSON. If I have a known starting point in the JSON, I'll often use a "base" list variable for that, and add a list for additional levels like this: list lBase; // higher level list lTarget. lBase = [whatever]; example: lTarget = ["image", "preview"]; string sURL; sURL = llJsonGetValue(sourcejson, lBase + lTarget); Each entry in the [specifiers] list just goes one level deeper into the JSON whether it's into a JSON_OBJECT or into a JSON_ARRAY. 1 Link to comment Share on other sites More sharing options...
Innula Zenovka Posted January 8, 2023 Author Share Posted January 8, 2023 Thanks! llJsonGetValue(body, ["items",0,"image","preview"]); does the trick. 1 Link to comment Share on other sites More sharing options...
Recommended Posts
Please take a moment to consider if this thread is worth bumping.
Please sign in to comment
You will be able to leave a comment after signing in
Sign In Now