JSON structure help needed

I am starting to set up a module that allows me to read in data from a web server in JSON format, and populate my app with data from the JSON.

Everything works fine with one set of data in the JSON, but I need to have multiple pieces of data in the file, for example:

This works fine:

{  
"title": "First",  
"info": {  
 "point": "133",  
 "foo": "144"  
 }  
}  

I can load and decode the file just fine, and get the data accordingly. As soon as I try to add a new object, with the same keys, but different values I get errors.

This produces a runtime error:

{  
"title": "First",  
"info": {  
 "point": "133",  
 "foo": "144"  
 }  
}  
{  
"title": "Second",  
"info": {  
 "point": "233",  
 "foo": "244"  
 }  
}  

And this will only read in the first bit of data:

{  
"title": "First",  
"info": {  
 "point": "133",  
 "foo": "144"  
 }  
"title": "First",  
"info": {  
 "point": "133",  
 "foo": "144"  
 }  
}  

I read on the JSON site that an object is declared using { }. Wrapping each piece of data in it’s own curly braces isn’t the answer, and neither is just adding in a second set of data.

Anyone point me in the write direction? [import]uid: 5317 topic_id: 13975 reply_id: 313975[/import]

I seem to have made some headway.

Wrapping everything in square brackets [] , and using curly’s { } to define each individual object, like so:

[  
{  
"title": "First",  
"info": {  
 "point": "133",  
 "foo": "144"  
 }  
},  
{  
"title": "Second",  
"info": {  
 "point": "233",  
 "foo": "244"  
 }  
}  
]  

at least gets me two separate tables returned. I need to modify my reading code to get the data… Progress! [import]uid: 5317 topic_id: 13975 reply_id: 51419[/import]

That’s basically the format I’m using for a project and I end up with an array:

[lua]local items = {}

items = json.decode(string)

for i=1,#items do
print(items[i].name)
print(items[i].address)
etc…
end[/lua]

my JSON data would be organized:

[code]
[{“name”:“Bill”, “address”:“123 main st.”},
{“name”:“Fred”, “address”:“bedrock”},
{“name”:“George”,'address":“Astrotown”}
]

My array would have 3 items in it.

Looks like you’re on the right track.
[import]uid: 19626 topic_id: 13975 reply_id: 51481[/import]

Thanks for the corroboration, rob.

I need to look at my format organization and make some decisions regarding structure.

I think I might actually be able to put things together like you did, as a single table holding all the necessary data, rather than a table with a table nested inside it.

Better to have to make these decisions up front, I always say. [import]uid: 5317 topic_id: 13975 reply_id: 51486[/import]

can you check my file out, tell me where I’m going wrong?

  
{  
 { /\* level pack one \*/  
 { /\* level 1 \*/  
 "score": 10000,  
 "hScore": 9000,  
 "amount": 3,   
 "shapes" : {  
 {"type": "rectangle", "x": 140, "y": 440, "width": 60, "height":10 },  
 {"type": "rectangle", "x": 0, "y": 0 , "width": 40, "height":40 },  
 {"type": "rectangle", "x": 0, "y": 0 , "width": 20, "height":20 }   
 }  
 }  
 { /\* level 2 \*/  
 "score": 10000,  
 "hScore": 9000,  
 "amount": 3,   
 "shapes" : {  
 {"type": "rectangle", "x": 140, "y": 440, "width": 60, "height":10 },  
 {"type": "rectangle", "x": 0, "y": 0 , "width": 40, "height":40 },  
 {"type": "rectangle", "x": 0, "y": 0 , "width": 20, "height":20 }   
 }  
 }  
 { /\* level 3 \*/  
 "score": 10000,  
 "hScore": 9000,  
 "amount": 3,   
 "shapes" : {  
 {"type": "rectangle", "x": 140, "y": 440, "width": 60, "height":10 },  
 {"type": "rectangle", "x": 0, "y": 0 , "width": 40, "height":40 },  
 {"type": "rectangle", "x": 0, "y": 0 , "width": 20, "height":20 }   
 }  
 }   
 }  
 { /\* level pack two \*/  
 { /\* level 1 \*/  
 "score": 10000,  
 "hScore": 9000,  
 "amount": 3,   
 "shapes" : {  
 {"type": "rectangle", "x": 140, "y": 440, "width": 60, "height":10 },  
 {"type": "rectangle", "x": 0, "y": 0 , "width": 40, "height":40 },  
 {"type": "rectangle", "x": 0, "y": 0 , "width": 20, "height":20 }   
 }  
 }  
 { /\* level 2 \*/  
 "score": 10000,  
 "hScore": 9000,  
 "amount": 3,   
 "shapes" : {  
 {"type": "rectangle", "x": 140, "y": 440, "width": 60, "height":10 },  
 {"type": "rectangle", "x": 0, "y": 0 , "width": 40, "height":40 },  
 {"type": "rectangle", "x": 0, "y": 0 , "width": 20, "height":20 }   
 }  
 }  
 { /\* level 3 \*/  
 "score": 10000,  
 "hScore": 9000,  
 "amount": 3,   
 "shapes" : {  
 {"type": "rectangle", "x": 140, "y": 440, "width": 60, "height":10 },  
 {"type": "rectangle", "x": 0, "y": 0 , "width": 40, "height":40 },  
 {"type": "rectangle", "x": 0, "y": 0 , "width": 20, "height":20 }   
 }  
 }   
 }  
}  

My errors is [python] bad argument #2 to ‘format’ (string expected, got table)
[/python]

I’m following the object example from here: http://www.json.org/fatfree.html

Which is used in the tutorial on the blog too.

Thanks. [import]uid: 87611 topic_id: 13975 reply_id: 54236[/import]

At a quick glance it looks like you’re missing “,” commas between objects. There are a good number of online JSON validators if you google “JSON Validator”

Here’s one: http://jsonlint.com/ [import]uid: 4596 topic_id: 13975 reply_id: 54290[/import]

It keeps giving me errors about expecting a string on the first line? Do I need to define the first array or something? [import]uid: 87611 topic_id: 13975 reply_id: 54310[/import]

As far as I know you can’t comment out lines in JSON data.

There are some great JSON examples here: http://json.org/example.html

{} are objects, [] are arrays

{ "stuff": "simple", "cowboys": [ { "name": "Bob", "age": 41, "married with children": false } ], "indians": [ { "name": "Runs With Hatchet", "age": 23.5, "married with children": false }, { "name": "Dances With Buffalo", "age": 33, "married with children": true, "children": [ { "name": "Pees Into The Wind", "age": 0.5 } ] } ] } [import]uid: 4596 topic_id: 13975 reply_id: 54341[/import]

@Lewis.Elliott.92 - I was able to edit the data you posted and get it to validate. Here is what I put together. Pardon the crazy indentation, I added a bunch to make things easier for me to see the balance of the brackets, and the forum seems to have added more of it’s own.

This validates in the JSONLint validator.

[ {"level\_pack\_one": { "level\_1":{ "score": 10000, "hScore": 9000, "amount": 3, "shapes":[ {"type": "rectangle", "x": 140, "y": 440, "width": 60, "height":10 }, {"type": "rectangle", "x": 0, "y": 0 , "width": 40, "height":40 }, {"type": "rectangle", "x": 0, "y": 0 , "width": 20, "height":20 } ] }, "level\_2":{ "score": 10000, "hScore": 9000, "amount": 3, "shapes":[ {"type": "rectangle", "x": 140, "y": 440, "width": 60, "height":10 }, {"type": "rectangle", "x": 0, "y": 0 , "width": 40, "height":40 }, {"type": "rectangle", "x": 0, "y": 0 , "width": 20, "height":20 } ] }, "level\_3":{ "score": 10000, "hScore": 9000, "amount": 3, "shapes":[ {"type": "rectangle", "x": 140, "y": 440, "width": 60, "height":10 }, {"type": "rectangle", "x": 0, "y": 0 , "width": 40, "height":40 }, {"type": "rectangle", "x": 0, "y": 0 , "width": 20, "height":20 } ] } } }, {"level\_pack\_two": { "level\_1":{ "score": 10000, "hScore": 9000, "amount": 3, "shapes":[ {"type": "rectangle", "x": 140, "y": 440, "width": 60, "height":10 }, {"type": "rectangle", "x": 0, "y": 0 , "width": 40, "height":40 }, {"type": "rectangle", "x": 0, "y": 0 , "width": 20, "height":20 } ] }, "level\_2":{ "score": 10000, "hScore": 9000, "amount": 3, "shapes":[ {"type": "rectangle", "x": 140, "y": 440, "width": 60, "height":10 }, {"type": "rectangle", "x": 0, "y": 0 , "width": 40, "height":40 }, {"type": "rectangle", "x": 0, "y": 0 , "width": 20, "height":20 } ] }, "level\_3":{ "score": 10000, "hScore": 9000, "amount": 3, "shapes":[ {"type": "rectangle", "x": 140, "y": 440, "width": 60, "height":10 }, {"type": "rectangle", "x": 0, "y": 0 , "width": 40, "height":40 }, {"type": "rectangle", "x": 0, "y": 0 , "width": 20, "height":20 } ] } } } ] [import]uid: 5317 topic_id: 13975 reply_id: 54350[/import]

Thanks for that mike, will take a look later, I suppose I can remove the level_pack_one and level_1 strings to identify the objects and arrays? I would like to use a counter within a for loop within my game to reference them instead. As I’m currently treating them as an array, within an array within an array using lua structures. I just need to convert to JSON tonight. [import]uid: 87611 topic_id: 13975 reply_id: 54425[/import]

Let me know if you have any trouble with accessing the data and I can lend a hand.

I just went through the hell (hell may be to strong a word…trouble is more like it, PITA works, too) of figuring out the way to do this in my app. [import]uid: 5317 topic_id: 13975 reply_id: 54453[/import]

Do you know why I can’t reference .shapes ?

[  
 [  
 [  
 {"score":10000},  
 {"hScore":9000},  
 {"amount":3},  
 {"shapes":[  
 {"type":"rectangle", "x":140,"y":440,"width":60,"height":10},  
 {"type":"rectangle", "x":140,"y":440,"width":60,"height":10},  
 {"type":"rectangle", "x":140,"y":440,"width":60,"height":10}  
 ]  
 }  
 ],  
 [  
 {"score":10000},  
 {"hScore":9000},  
 {"amount":3},  
 {"shapes":[  
 {"type":"rectangle", "x":140,"y":440,"width":60,"height":10},  
 {"type":"rectangle", "x":140,"y":440,"width":60,"height":10},  
 {"type":"rectangle", "x":140,"y":440,"width":60,"height":10}  
 ]  
 }  
 ],  
 [  
 {"score":10000},  
 {"hScore":9000},  
 {"amount":3},  
 {"shapes":[  
 {"type":"rectangle", "x":140,"y":440,"width":60,"height":10},  
 {"type":"rectangle", "x":140,"y":440,"width":60,"height":10},  
 {"type":"rectangle", "x":140,"y":440,"width":60,"height":10}  
 ]  
 }  
 ],  
 [  
 {"score":10000},  
 {"hScore":9000},  
 {"amount":3},  
 {"shapes":[  
 {"type":"rectangle", "x":140,"y":440,"width":60,"height":10},  
 {"type":"rectangle", "x":140,"y":440,"width":60,"height":10},  
 {"type":"rectangle", "x":140,"y":440,"width":60,"height":10}  
 ]  
 }  
 ]  
  
 ]  
]  

I’m using:

 config [first array][second array].shapes

trying to iterate through it using:

for i, child in ipairs(config[first array][second array].shapes)

Also have you worked out how to write to certain values in these json files? I’ve pretty much got the loading sorted just a bit of trouble with the saving of certain values in these arrays!

Cheers. [import]uid: 87611 topic_id: 13975 reply_id: 54724[/import]

I honestly haven’t had a chance to look at this yet. I’m currently in the last few days of finishing off an app, so I will jump in when I have a few free minutes. [import]uid: 5317 topic_id: 13975 reply_id: 54807[/import]

I’m making an app for my band and I was thinking of downloading a json file from a www location with our gigs etc and add them to a tableview.

How would I structure my json file the best way? I have made a few different ones but they don’t look right but they validates correctly.

Basically what I want to achieve is;

  • display month in the category bar,
  • display date in the icon field as an image or just a number,
  • display place as the title in the tableView
  • display time and admission fee in subtitle
  • display description, address and perhaps an image or mapView in a detailScreen when table cell is

Here’s the best looking json I made, does anyone have a better structure?

[  
 {  
 "month": "October"  
 },  
 {  
 "date": "1st"  
 },  
 {  
 "place": "The Big Bar",  
 "time": "21.00",  
 "admission": "$20",  
 "description": "Only hot chicks allowed...",  
 "address": "21 Down Street"  
 },  
 {  
 "date": "5th"  
 },  
 {  
 "place": "The Nice Bar",  
 "time": "22.00",  
 "admission": "$10",  
 "description": "Only hot chicks allowed...",  
 "address": "21 Nude Street"  
 },  
 {  
 "month": "November"  
 },  
 {  
 "date": "10th"  
 },  
 {  
 "place": "The Big Bar",  
 "time": "21.00",  
 "admission": "$20",  
 "description": "Only hot chicks allowed...",  
 "address": "21 Drive Street"  
 },  
 {  
 "date": "15th"  
 },  
 {  
 "place": "The Nice Bar",  
 "time": "22.00",  
 "admission": "$10",  
 "description": "Only hot chicks allowed...",  
 "address": "21 Jump Street"  
 }  
]  

[import]uid: 34126 topic_id: 13975 reply_id: 61456[/import]

Anyone had a chance to give this a quick look?

Cheers
David [import]uid: 34126 topic_id: 13975 reply_id: 61801[/import]

Why not do this instead:

 {  
 "month": "October",  
 "date": "1st"  
 "place": "The Big Bar",  
 "time": "21.00",  
 "admission": "$20",  
 "description": "Only hot chicks allowed...",  
 "address": "21 Down Street"  
 },  
 {  
 "month": "October",  
 "date": "5th"  
 "place": "The Nice Bar",  
 "time": "22.00",  
 "admission": "$10",  
 "description": "Only hot chicks allowed...",  
 "address": "21 Nude Street"  
 },  
 {  
 "month": "November",  
 "date": "10th",  
 "place": "The Big Bar",  
 "time": "21.00",  
 "admission": "$20",  
 "description": "Only hot chicks allowed...",  
 "address": "21 Drive Street"  
 },  
 {  
 "month": "November",  
 "date": "15th",  
 "place": "The Nice Bar",  
 "time": "22.00",  
 "admission": "$10",  
 "description": "Only hot chicks allowed...",  
 "address": "21 Jump Street"  
 }  
]  

or better yet:

 {  
 "date": "2001-11-15T22:00:00-400",  
 "place": "The Nice Bar",  
 "admission": "$10",  
 "description": "Only hot chicks allowed...",  
 "address": "21 Jump Street"  
 }  
  

Then you would parse the date to get the various data bits:

(this is untested)

year, month, day, hour, min, sec, tz = string.match(data.date,
“(%d+)%-(%d+)%-(%)T(%d+):(%d+)%:*(%d+)([%-%+]%d+)”)
Basically there is no reason to make your JSON complex by having different table types for each entry (Month structure, day of month structure, rest of event structure) and have to keep track of which is which.

Using the method I suspect its simply:

data[1].month
data[1].date
data[1].place
etc. A simple one dimensional array of information.

Then if you’re using Corona’s TableView widget, you could do this:

[lua]entries = json.decode(mydata)
category = “”
local j = 1
for i = 1, #entries do
if entries[i].month == category then
– print("Adding item " … stories[i].title)
itemData[j] = {}
itemData[j].icon = itemIcon;
itemData[j].title = {
label = entries[i].place,
font = “Helvetica-Bold”,
size = 18,
color = { 0, 0, 0 }, – red, green, blue
left = 10,
top = 10
}
itemData[j].subtitle = {
label = entries[i].time … " - " … entries[i].admission,
font = “Helvetica”,
size = 14,
color = { 150, 150, 150 },
left = 10,
top = 0
}
itemData[j].onRelease = onItemRelease
else
category = entries[i].month
itemdata[j].CategoryName = category
end
j = j + 1
end
myList:sync(itemData)[/lua]

of course you would have to figure out the code for getting a date Icon in place. [import]uid: 19626 topic_id: 13975 reply_id: 61860[/import]

Thanks Rob,
There’s something strange with this code, I get an error at line 31 and I’m so confused since that is the print function that is commented out so nothing shows up in the Simulator.

I’m using the tabBar sample as my starting point.

screen2.lua

module(..., package.seeall)  
  
local json = require("json")  
  
function new()  
 local g = display.newGroup()  
  
 local newToolbar = newToolbar  
 local newButton = newButton  
 local newTableView = newTableView  
 local myNavBar;  
 local myBackBtn;  
 local background;  
  
 local entries;  
 local category;  
 local myTableView;  
  
 -- Forward references for downloading of the json file.  
 local networkListener;  
 local fileName = "gigs.json";  
 local fileURL = "";  
  
  
 entries = json.decode(myData)  
 print(entries)  
 category = ""  
 local j = 1  
 for i = 1, #entries do  
 if entries[i].month == category then  
 --print("Adding item " .. entries[i].title)  
 itemData[j] = {}  
 itemData[j].icon = itemIcon;  
 itemData[j].title = {  
 label = entries[i].place,  
 font = "Helvetica-Bold",  
 size = 18,  
 color = { 0, 0, 0 }, -- red, green, blue  
 left = 10,  
 top = 10  
 }  
 itemData[j].subtitle = {  
 label = entries[i].time .. " - " .. entries[i].admission,  
 font = "Helvetica",  
 size = 14,  
 color = { 150, 150, 150 },  
 left = 10,  
 top = 0  
 }  
 itemData[j].onRelease = onItemRelease  
 else  
 category = entries[i].month  
 itemdata[j].CategoryName = category  
 end  
 j = j + 1  
 end  
  
 local myTableView = newTableView   
 {   
 y = 64,   
 rowHeight = 61,   
 height = 384,   
 width = 320,   
 backgroundColor = "none",  
 bottomLineColor = {218, 230, 241},  
 rowColor = {231, 235, 237},  
 downColor = {218, 230, 241},  
 }  
 g:insert( myTableView.view )  
 myTableView:sync(itemData)  
  
 myNavBar = newToolbar ("Gigs")  
  
 g:insert(myNavBar.view)  
  
 function g:cleanUp()  
  
 -- Remove widgets.  
 display.remove(myNavBar);  
 myNavBar = nil;  
 display.remove(myTableView);  
 myTableView = nil;  
  
 -- Remove the entire group.  
 g:removeSelf();  
 g = nil;  
  
 print(" clean screen2!");  
 end  
  
 return g  
end  
  

gigs.json

[  
 {  
 "month": "October",  
 "date": "1st",  
 "place": "The Big Bar",  
 "time": "21.00",  
 "admission": "$20",  
 "description": "Only hot chicks allowed...",  
 "address": "21 Down Street"  
 },  
 {  
 "month": "October",  
 "date": "5th",  
 "place": "The Nice Bar",  
 "time": "22.00",  
 "admission": "$10",  
 "description": "Only hot chicks allowed...",  
 "address": "21 Nude Street"  
 },  
 {  
 "month": "October",  
 "date": "5th",  
 "place": "The Nice Bar",  
 "time": "22.00",  
 "admission": "$10",  
 "description": "Only hot chicks allowed...",  
 "address": "21 Nude Street"  
 },  
 {  
 "month": "October",  
 "date": "5th",  
 "place": "The Nice Bar",  
 "time": "22.00",  
 "admission": "$10",  
 "description": "Only hot chicks allowed...",  
 "address": "21 Nude Street"  
 },  
 {  
 "month": "October",  
 "date": "5th",  
 "place": "The Nice Bar",  
 "time": "22.00",  
 "admission": "$10",  
 "description": "Only hot chicks allowed...",  
 "address": "21 Nude Street"  
 },  
 {  
 "month": "October",  
 "date": "5th",  
 "place": "The Nice Bar",  
 "time": "22.00",  
 "admission": "$10",  
 "description": "Only hot chicks allowed...",  
 "address": "21 Nude Street"  
 },  
 {  
 "month": "November",  
 "date": "10th",  
 "place": "The Big Bar",  
 "time": "21.00",  
 "admission": "$20",  
 "description": "Only hot chicks allowed...",  
 "address": "21 Drive Street"  
 },  
 {  
 "month": "November",  
 "date": "10th",  
 "place": "The Big Bar",  
 "time": "21.00",  
 "admission": "$20",  
 "description": "Only hot chicks allowed...",  
 "address": "21 Drive Street"  
 },  
 {  
 "month": "November",  
 "date": "10th",  
 "place": "The Big Bar",  
 "time": "21.00",  
 "admission": "$20",  
 "description": "Only hot chicks allowed...",  
 "address": "21 Drive Street"  
 },  
 {  
 "month": "November",  
 "date": "10th",  
 "place": "The Big Bar",  
 "time": "21.00",  
 "admission": "$20",  
 "description": "Only hot chicks allowed...",  
 "address": "21 Drive Street"  
 },  
 {  
 "month": "November",  
 "date": "15th",  
 "place": "The Nice Bar",  
 "time": "22.00",  
 "admission": "$10",  
 "description": "Only hot chicks allowed...",  
 "address": "21 Jump Street"  
 }  
]  

[import]uid: 34126 topic_id: 13975 reply_id: 62059[/import]

Can you paste the error here? [import]uid: 19626 topic_id: 13975 reply_id: 62088[/import]

Here’s the message.

Runtime error  
 Nil string: ''  
stack traceback:  
 [C]: ?  
 [C]: in function '?'  
 ?: in function <?:269>  
 (tail call): ?  
 ...8ncjymmw0btj00000gn/T/TemporaryItems/212/screen2.lua:31: in function 'new'  

And another offTopic question, changing tableView Cell colors does not work. I tried it in the Widget sample and it didn’t change. Does anyone have a clue why it doesn’t, when reading the API I assume it should be done the way I did it?

Thanks Rob.
David [import]uid: 34126 topic_id: 13975 reply_id: 62165[/import]

Several questions:

 local newToolbar = newToolbar  
 local newButton = newButton  
 local newTableView = newTableView  

What’s going on here? Are newtoolbar, newButton global variables where youv’e done a “local newButton = widget.newButton” somewhere else? If thats the case, why not just require “widget” in main.lua and use them here as “widget.newButton”???

Where are you actually reading the JSON file? Where is “myData” being initialized? At some point, you have to use the file IO system to read the JSON file into memory into a string that gets passed to json.decode…

 local fileName = "gigs.json";  
 local fileURL = "";  
  
  
 entries = json.decode(myData)  

You need something like this:

 local path = system.pathForFile( fileName, system.ResourceDirectory)  
 local contents = ""  
 local file = io.open( path, "r" )  
 if file then  
 -- read all contents of file into a string  
 local contents = file:read( "\*a" )  
 entries = json.decode(contents);  
 io.close( file )  
 ...   
 --process the JSON file  
 ...  
 end  

BTW: the error makes no sense, so I’m suspecting something is confused by not having data. [import]uid: 19626 topic_id: 13975 reply_id: 62171[/import]