nodemcu學習(四)-- json格式轉化為table格式
這是我學的最糟糕的一個模組了, 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"]) 來看看結果吧: