这是我学的最糟糕的一个模块了, lua中的json形式的[] 和{} 转化为table是把我弄的头昏脑涨, 归结原因是对lua的语法不够明确,废话少说, 我们开始来今天的重点, 从json形式中提取我们想要的键或者键值.
华丽的分割线
lua中内置了一个json和table形式相互转化的模块--sjson模块
sjson的官方api介绍在这:https://nodemcu.readthedocs.io/en/master/en/modules/sjson/#sjsondecoder
我们重点来说我们今天要用的api吧:sjson.decoder()
语法:sjson.decode(str[, opts])
参数: str: 需要转化的json字符串(注意是字符串), 一开始我没注意是字符串, 报错, 找了我含就 好久才发现
opts:选择可选的选项表。 可能的条目是:
深度编码表所需的最大编码深度。 默认值为20,几乎适用于所有情况。
null将字符串值视为null。
metatable一个表,用作返回对象中所有新表的元表。 请参阅上面 sjson.decoder()描述中的metatable部分
有这个函数就ok了, 开始我们的转换之旅吧.
首先要有一个json形式的字符串, 我就拿我上堂课在onenet平台上请求得到的一串数据拿来做实验吧:
sampleJson = '{"errno":0,"data":{"count":1,"datastreams":[{"datapoints":[{"at":"2018-10-17 12:45:49.000","value":34}],"id":"shidu_adjust"}]},"error":"succ"}';
这一个 json数据很复杂吧, 对于复杂结构的数据json数据 我们要理清谁是键, 谁又是键值, 而且还要理清, 那个json对象包含哪个对象, json对象中的{} 和[] 在这顺便补充一下吧, 在 JSON里[]是 Array(也就是数组),{}是Ojbect(也就是对象, 如果你想在一个键中包含多个json对象, 那么就得用数组形式
那么我们来分解这个json数据吧, 理清结构, 那如何进行分解呢? 这里介绍我的一种方法, 倘若有更好得方法, 我们可以互相讨论:
我主要是借助{} [] 和, 三个符号进行区分的, 先找到最外面的一对{}, 依次从左往右按照遇见在我们找的{}内而不在新出现的{}内的逗号就切开, 这句话有点拗口, 总而言之就是我们可以这样做: 找到最外层的一对{}后, 再找次外层的一对{}, 夹在最外层中不在次外层内的逗号切开, 第一次切后是下面这样的:
{
"errno":0,
"data":{"count":1,"datastreams":[{"datapoints":[{"at":"2018-10-17 12:45:49.000","value":34}],"id":"shidu_adjust"}]},
"error":"succ"
}
第二步呢: 就是把切完后的再切还有嵌套结构的json对象, 比如途中的data对象, 方法还是一样的, 切完后的结果如下:
{
"errno":0,
"data":{
"count":1,
"datastreams":[{"datapoints":[{"at":"2018-10-17 12:45:49.000","value":34}],"id":"shidu_adjust"}]
},
"error":"succ"
}
依次下去, 看到了[]号 不用怕, []表示是含有多个对象的json数组, 数组的元素用逗号隔开, 那么是不是和前面的类似了?, 下一步的:
{
"errno":0,
"data":{
"count":1,
"datastreams":[
{"datapoints":[{"at":"2018-10-17 12:45:49.000","value":34}],
"id":"shidu_adjust"}
]
},
"error":"succ"
}
再下一步:
{
"errno":0,
"data":{
"count":1,
"datastreams":[
{"datapoints":[
{"at":"2018-10-17 12:45:49.000",
"value":34}
],
"id":"shidu_adjust"}
]
},
"error":"succ"
}
到此结构已经完全理清, 同学会问我, 理清这个有什么用, 我只想说用处可大了, 当你要查找某个键的键值的时候, 可以很快找出来.
来, 我们用api转化一下吧.:data = sjson.decode(sampleJson);顺便打印一下吧:print(data), 结果如下:
我的天, 打印的什么鬼东西, 我还是问问度娘吧, 度娘说, lua打印table对象时只会打印出table的内存地址, 这可怎么办..... 我想看打印的结果呢, 别急, 还有伟大的度娘呢, 找到一个打印table的脚本, 试试效果吧, 脚本代码:
function print_table ( t )
local print_r_cache={}
local function sub_print_r(t,indent)
if (print_r_cache[tostring(t)]) then
print(indent.."*"..tostring(t))
else
print_r_cache[tostring(t)]=true
if (type(t)=="table") then
for pos,val in pairs(t) do
if (type(val)=="table") then
print(indent.."["..pos.."] => "..tostring(t).." {")
sub_print_r(val,indent..string.rep(" ",string.len(pos)+8))
print(indent..string.rep(" ",string.len(pos)+6).."}")
elseif (type(val)=="string") then
print(indent.."["..pos..'] => "'..val..'"')
else
print(indent.."["..pos.."] => "..tostring(val))
end
end
else
print(indent..tostring(t))
end
end
end
if (type(t)=="table") then
print(tostring(t).." {")
sub_print_r(t," ")
print("}")
else
sub_print_r(t," ")
end
print()
end
试试print_table(data), 结果如下:
table: 0x3fff0078 {
[errno] => 0
[data] => table: 0x3fff0078 {
[count] => 1
[datastreams] => table: 0x3fff0c20 {
[1] => table: 0x3fff0dc8 {
[id] => "shidu_adjust"
[datapoints] => table: 0x3fff0220 {
[1] => table: 0x3fff0ea8 {
[at] => "2018-10-17 12:45:49.000"
[value] => 34
}
}
}
}
}
[error] => "succ"
}
小伙伴们, 是不是很惊奇, 这不是我们上面理清的那个结构吗, 只是多了table的地址还有[1], 我们惊奇的发现有[1]的地方刚好出现[], 奥... 那是应为[]是数组, 而[1]代表数组的第一个元素(lua的数组下标是从1开始的)我们来个最难的吧, 如果我们想打印value的值那应该怎么写? 思考一会, 等会放出答案
答案应该是: print(data["data"]["datastreams"][1]["datapoints"][1]["value"]) 来看看结果吧: