Decode and Parse JSON to Lua - json

I have following JSON data I would like to decode to Lua to access each the publish_topic and sample_rate value.
{"00-06-77-2f-37-94":{"publish_topic":"/stations/test","sample_rate":5000}}
If I understand correctly the Lua table will look like this:
{00-06-77-2f-37-94 = "publish_topic":"/stations/test","sample_rate":5000}
Next I would go through the table to save each value into a local variable.
However, if I try printing out the values of the table (using following code), I get 'nil' as return. Is the code for reading table values wrong?
Does the table have two values or is it just the one: ["publish_topic":"/stations/test","sample_rate":5000] ?
lua_value = JSON:decode(data)
for _,d in pairs(lua_value) do
print(lua_value[d])
end
local topic = lua_value[0]
local timer = lua_value[1]
end
Edit: I am using following JSON library for Lua: http://regex.info/blog/lua/json
Edit2: #Piglet: I implemented your script and modified it by adding a table (conversionTable) in which both elements "publish_topic":"/stations/test" and "sample_rate:5000" would be respectively saved in the variables pubtop and rate. When I however print each of both variables, nil ist returned in both cases.
How can I extract the information out of this table to save in variables?
Ultimately I actually only would like to save the values "/stations/test" and "5000" into these variables. Would I need to parse each of the elements above to get these or is there another way?
local pubtop
local rate
local function printTable(t)
local conversionTable = {}
for k,v in pairs(t) do
if type(v) == "table" then
conversionTable [k] = string.format("%q: {", k)
printTable(v)
print("}")
else
print(string.format("%q:", k) .. v .. ",")
end
end
pubtop = conversionTable[0]
rate = conversionTable[1]
end
local lua_value
local function handleOnReceive(topic, data, _, _)
print("handleOnReceive: topic '" .. topic .. "' message '" .. data .. "'")
-- This sample publishes the received messages to test/topic2
print(data)
lua_value = JSON:decode(data)
printTable(lua_value)
print(pubtop)
print(rate)
end
client:register('OnReceive', handleOnReceive)

I don't know which json library you're using so I can't tell you wether JSON:decode(data) is the correct way.
Assuming lua_value would like like so:
local lua_value = {
["00-06-77-2f-37-94"] = {
publish_topic = "/stations/test",
sample_rate = 5000
}
}
Then your loop
for _,d in pairs(lua_value) do
print(lua_value[d])
end
will indeed print nil.
lua_value has a single element at key "00-06-77-2f-37-94" which is a table.
Each loop iteration will give you a key value pair. So d is actually the value and hence the inner table of lua_value
So you're actually doing this:
local innerTable = lua_value["00-06-77-2f-37-94"]
print(lua_value[innerTable])
Of course lua_value[innerTable] is nil.
Edit:
Try something like
function printTable(t)
for k,v in pairs(t) do
if type(v) == "table" then
print(string.format("%q: {", k))
printTable(v)
print("}")
else
print(string.format("%q:", k) .. v .. ",")
end
end
end
printTable(lua_value)

Related

String passed to JSON library turns into a table

When I execute this code (Windows 10) i get an error from within the library.
local json = loadfile("json.lua")()
local handle = io.popen("curl \"https://someurl.com\"")
local result = handle:read("*all")
handle:close()
local output = json:decode(result)
The error in the console:
lua: json.lua:377: expected argument of type string, got table
stack traceback:
[C]: in function 'error'
json.lua:377: in method 'decode'
monitor.lua:10: in main chunk
[C]: in ?
I'm running the code on Windows 10 with a console and using this library: https://github.com/rxi/json.lua
This function always returns the same error, even if I try different types of arguments, i.e. numbers or strings.
function json.decode(str)
if type(str) ~= "string" then
error("expected argument of type string, got " .. type(str))
end
local res, idx = parse(str, next_char(str, 1, space_chars, true))
idx = next_char(str, idx, space_chars, true)
if idx <= #str then
decode_error(str, idx, "trailing garbage")
end
return res
end
local output = json:decode(result)
is syntactic sugar for
local output = json.decode(json, result)
json is a table.
Hence inside function json.decode the following if statement is entered:
if type(str) ~= "string" then
error("expected argument of type string, got " .. type(str))
end
which produces the observed error.
To fix this you can either change the function definiton to
function json:decode(str)
-- code
end
Or you call
local output = json.decode(result)
You should pick the second one as changing the json library will affect code that already uses json.decode as intended by the author.

Save decoded JSON values in Lua Variables

Following script describes the decoding of a JSON Object, that is received via MQTT. In this case, we shall take following JSON Object as an example:
{"00-06-77-2f-37-94":{"publish_topic":"/stations/test","sample_rate":5000}}
After being received and decoded in the handleOnReceive function, the local function saveTable is called up with the decoded object which looks like:
["00-06-77-2f-37-94"] = {
publish_topic = "/stations/test",
sample_rate = 5000
}
The goal of the saveTable function is to go through the table above and assign the values "/stations/test" and 5000 respectively to the variables pubtop and rate. When I however print each of both variables, nil is returned in both cases.
How can I extract the values of this table and save them in mentioned variables?
If i can only save the values "publish_topic = "/stations/test"" and "sample_rate = 5000" at first, would I need to parse these to get the values above and save them, or is there another way?
local pubtop
local rate
local function saveTable(t)
local conversionTable = {}
for k,v in pairs(t) do
if type(v) == "table" then
conversionTable [k] = string.format("%q: {", k)
printTable(v)
print("}")
else
print(string.format("%q:", k) .. v .. ",")
end
end
pubtop = conversionTable[0]
rate = conversionTable[1]
end
local lua_value
local function handleOnReceive(topic, data, _, _)
print("handleOnReceive: topic '" .. topic .. "' message '" .. data .. "'")
print(data)
lua_value = JSON:decode(data)
saveTable(lua_value)
print(pubtop)
print(rate)
end
client:register('OnReceive', handleOnReceive)
previous question to thread: Decode and Parse JSON to Lua
The function I gave you was to recursively print table contents. It was not ment to be modified to get some specific values.
Your modifications do not make any sense. Why would you store that string in conversionTable[k]? You obviously have no idea what you're doing here. No offense but you should learn some basics befor you continue.
I gave you that function so you can print whatever is the result of your json decode.
If you know you get what you expect there is no point in recursively iterating through that table.
Just do it like that
for k,v in pairs(lua_value) do
print(k)
print(v.publish_topic)
print(v.sample_rate)
end
Now read the Lua reference manual and do some beginners tutorials please.
You're wasting a lot of time and resources if you're trying to implement things like that if you do not know how to access the elements of a table. This is like the most basic and important operation in Lua.

Can I use a value stored in a table as a key in another table?

I'm new to LUA and I still haven't gotten the hang of how classes work in LUA, so my question
probably has a very simple answer. I'm trying to make a function that takes a CSV file and turns it into a lua table.
The input file would be something like this
PropertyKey1,Propertykey2,Propertykey3
object1property1,object1property2,object1property3
object2property1,object2property2,object2property3
object3property1,object3property2,object3property3
and I want the resulting lua table to look something like this
objects = {
{
PropertyKey1 = object1property1
PropertyKey2 = object1property2
PropertyKey3 = object1property3
}
{
PropertyKey1 = object2property1
PropertyKey2 = object2property2
PropertyKey3 = object2property3
}
{
PropertyKey1 = object3property1
PropertyKey2 = object3property2
PropertyKey3 = object3property3
}
}
this is what I have thus far
function loadcsv(path)
local OutTable = {}
local file = io.open(path, "r")
local linecount = 0
for line in file:lines() do
local data = {}
local headers = {}
local headerkey = 1
if linecount < 1 then
for val in line:gmatch("([^,]+),?") do
table.insert(headers, val)
end
else
for word in line:gmatch("([^,]+),?") do
key = headers[headerkey]
data[headerkey] = word
headerkey = headerkey + 1
table.insert(OutTable, data)
end
end
linecount = linecount + 1
end
file:close()
return OutTable
end
The above code does not run. When I try to print any of the values, they come as nil.
The problem is this bit
key = headers[headerkey]
data[headerkey] = word
I wanted to use the values I stored in one table as keys on the second table, but it looks like since LUA only passes the references, that doesn't work.
I did a quick experiment to confirm it. I first set up 2 tables.
test = {}
test2 = {}
test[1]={"index"}
key = test[1]
key2 = "index"
First I tried assigning the value directly form the table
test2[test[1]] = "text"
print(test2.index) --This did not work
then I tried going trough another variable
test2[key] = "texto"
print(test2.index) --This did not work
I even tried using tostring()
key = tostring(test[1])
test2[key] = "texto"
print(test2.index) --This did not work
I wrote the string directly in the variable "key2" to confirm that I was using the right notation.
test2[key2] = "text"
print(test2.index) --This one worked
I read a bit on metatables, but I'm not fully clear on those. Would that be the simplest way to do what I'm trying to do, or is my approach flawed in some other way?
key = headers[headerkey]
key is not used so why assign a value to it?
data[headerkey] = word
headerkey is a numeric key. You start at 1 for each line and add 1 for each word in a line. So you end up with
data = {
[1] = "object1property1",
[2] = "object1property2",
[3] = "object1property3"
}
Instead of the intended
data = {
PropertyKey1 = "object1property1",
PropertyKey2 = "object1property2",
PropertyKey3 = "object1property3"
}
So you probably meant to write
local key = headers[headerkey]
data[key] = word
But you have to move headers out of the loop. Otherwise you'll end up with an empty table for line 1 resulting in key being nil which would cause Lua errors for using a nil table index.
The following line is called for every word
table.insert(OutTable, data)
You need to do this for every line!
Your code basically produces this output:
local tableA = {"object1property1", "object1property2", "object1property3"}
local tableB = {"object2property1", "object2property2", "object2property3"}
local tableC = {"object3property1", "object3property2", "object3property3"}
OutTable = {
tableA, tableA, tableA, tableB, tableB, tableB, tableC, tableC, tableC
}
I suggest you formulate your program in your first language and then translate it into Lua. This helps to avoid such errors.
Your problem is not related to metatables, classes or anything else mentioned. You simply used the wrong variable and messed up your inner loop.

understanding how a lua function does work?

I have a HTML project that uses mutiple lua scripts , I have big issue unterstanding the functionality of one function ( I'm new to lua) :
........................
all the requires have been done and the paths are also defined
local fs = require "lfs"
local const = {}
for num = 1, 14 do
const[num] = assert(
dofile (const_path .. mkfilename(num)),
"Failed to load constant configuration ".. num ..".")
end
local function file_number() --this is the function that causes me a headach
local ci, co, num = ipairs(const)-- when I print num is 0 and ci,co are nil
local vi, vo, _ = fs.dir(virt_path)-- what does _ mean here ?
local function vix(o)
local file = vi(o)
if file == nil then return nil end
local number = file:match("^(%d+).lua$")
if number == nil then return vix(o) end
return tonumber(number)
end
local function iter(o, num)
return ci(o.co, num) or vix(o.vo, num)---where is ci defined or impplemented
end
return iter, {co=co, vo=vo}, num-- what 's the return value here ?
end
the function works but I still don't understand why and how, I 'll be greatfull for any hint.
_ is conventionally a throw-away variable.
In this case though it serves no purpose and could just as easily be left out entirely.
ci should be a function and co should be a table there.
Similarly (though I can't say for sure about vo) for vi and vo.
That function is constructing its own iterator using the iterator functions and state returns from the ipairs and fs.dir functions.
The line return iter, {co=co, vo=vo}, num is returning an interator function, a table for state, and the initial loop variable (0 from the initial ipairs call).
When used in a loop that will loop over the values from ci and vix.

JSON network request not working with variables in Coronasdk

I have written the following code to send my gps locations saved in a Lua table to parse.com; the display.newText is a test to see if the Lua table data works properly which does so. The problem is that the POST network request doesn't work with my "message" table when used as the JSON parameter. Although exact what you see is working when I remove the -- from the following code. This defines the "message" table variables again. I use Corona SDK.
function post ( message )
test12 = display.newText( message["x1"] .. message["y1"] .. message["x2"] .. message["y2"]..message["v"], 150, time/100, "Verdana-Bold", 10 )
--message = { x1 = 22.312456, y1 = 22.312456, x2 = 22.312456, y2 = 22.312456, v = 10 }
params.body = json.encode ( message )
network.request( baseUrl .. objectClass, "POST", networkListener, params)
end
I think you need to have a better understanding of what Parse is looking for. I don't know Parse well enough to tell you what it is, but HTTP POST requires a body that is a set of HTTP Query String style key-value pairs. We've seen GET use things like:
http:/somesite.com/someurl.php?key=value&key2=value&key3=value
HTTP GET is limited to like 255 characters and the values have to be URLencoded.
HTTP POST is just like GET but it allows longer blocks of data to be sent on the input stream of the device These blocks of data are still Query String key-value pairs. I would expect the body statement (though not for your usage of Parse) to be something like:
params.body = "key=value&key2=value&key3=value" where the values of course could be much longer and any values properly URL encoded. Just shoving a block of JSON data in there isn't going to be something a POST script would parse. Perhaps something like:
params.body = "query=" .. urlencode( json.encode( someLuaTable ) )
You can use this URL encoding function:
function urlencode(str)
if (str) then
str = string.gsub (str, "\n", "\r\n")
str = string.gsub (str, "([^%w ])",
function (c) return string.format ("%%%02X", string.byte(c)) end)
str = string.gsub (str, " ", "+")
end
return str
end
But you need to figure out what key Parse wants for its input.
Your message has not the right format.
try this:
message = {"x1":22.312456,"y1":22.312456,"x2":22.312456,"y2":22.312456,"v":10}
cheers,
Felix
The issue was the Corona changes the variable to string while parse.com expected numbers. I simply multiplied all the table variables by 1 and then the whole things works ok.
function post ( message )
test12 = display.newText( message["x1"] .. message["y1"] .. message["x2"] .. message["y2"]..message["v"], 150, time/100, "Verdana-Bold", 10 )
--message = { x1 = 22.312456, y1 = 22.312456, x2 = 22.312456, y2 = 22.312456, v = 10 }
message["x1"] = message["x1"]*1
message["y1"] = message["y1"]*1
message["y2"] = message["y2"]*1
message["x2"] = message["x2"]*1
message["v"] = message["v"]*1
params.body = json.encode ( message )
network.request( baseUrl .. objectClass, "POST", networkListener, params)
end
If you have similar issues with Sqlite in corona that's the way to fix it.