JSON
json_decode / json_encode / json_null / json_pick / sd_json_pick
HTTPの応答や設定ファイルでよく使うJSONと、Luaのテーブルを相互に変換します。Luaで書いたJSONライブラリより速く、スクリプトの大きさも食いません。
pico.json_decode
pico.json_decode(text: string [, keep_null: boolean]) -> value | nil, error: string | nil
JSON文字列をLuaの値にします。失敗すると nil と理由(誤りの位置つき)を返します。
local t, err = pico.json_decode('{"name":"たろう","scores":[10,20.5],"ok":true}')
if not t then pico.log("JSONが不正: " .. err) return end
print(t.name, t.scores[2], t.ok) -- たろう 20.5 true
- 整数は整数(
math.typeが"integer")、小数や1e3のような指数表記は小数になります。Luaの整数(32bit、約±21億)に収まらない整数は小数になります(下の「数の範囲」)。 - 文字列のエスケープ(
\n\"\u3042とサロゲートペア)はUTF-8に戻されます。対になっていないサロゲートはU+FFFDです。 nullは既定ではnilになります(オブジェクトのキーは消え、配列は穴になります)。keep_nullをtrueにするとpico.json_nullという目印に置き換わるので、nullと「キーが無い」を区別できます。- 入れ子は16段、入力は64KiBまでです。超えると失敗します。
- 前後の空白は許されますが、末尾の余分な文字やカンマ、単引用符、
01のような先頭の0は不正です。
pico.json_encode
pico.json_encode(value) -> text: string | nil, error: string | nil
Luaの値をJSON文字列にします。失敗すると nil と理由を返します。
local body = pico.json_encode({ name = "たろう", scores = {10, 20}, ok = true })
pico.http_request("POST", url, body, "application/json", on_done)
- キーが
1..nの整数のテーブルは配列になります(穴はnullで埋めます:{1,nil,3}→[1,null,3])。キーが文字列のテーブルはオブジェクトになります。空のテーブルは[]になります。 - 書けないもの: 関数・スレッド・userdata、
NaNと無限大、文字列以外のキーを持つオブジェクト、入れ子が16段を超えるテーブル(循環参照も同じ理由で失敗します)、出力が64KiBを超えるもの。 - オブジェクトのキーの順序は決まっていません(出力を文字列として比べず、
json_decodeで戻して比べてください)。 pico.json_nullとnil(トップレベル)はnullになります。
pico.json_null
pico.json_null -- 値(lightuserdata)
json_decode(text, true) が null の代わりに返す目印で、json_encode に渡すと null になります。
pico.json_pick
pico.json_pick(text: string, paths: {string} [, opts: table]) -> values: table, truncated: table | nil
-> nil, error: string
-> nil, error: string
JSONから指定したパスの値だけを取り出します。json_decode は文書全体をLuaの表にするので、数KB〜数十KBの応答から数個の値が欲しいだけのときにLuaのメモリを大きく使います。json_pick は文書を先頭から読み流し、頼んだ値だけをLuaに作ります。
- パスはキーを
.でつなぎ、配列は1始まりの番号で書きます("item.artists.1.name")。一番外が配列なら"2"、"2.x"。 - パスの最後に
#を付けると、その配列/オブジェクトの要素の数になります("item.artists#"、一番外は"#")。 - 結果は
{[パス] = 値}の表です。値は文字列・数(整数は整数)・真偽値。見つからないパスとnullは入りません(opts.keep_null = trueならnullはpico.json_null)。オブジェクトや配列そのものは取れません(中の値か#を指定します)。 - 文字列は255バイトまでで、長いものは文字の途中で切らずに切り詰めます。切り詰めた値があれば2番目の戻り値に
{[パス] = true}が入ります(無ければnil)。 - パスは1〜32個、1つ510バイトまで。キーは47バイトを超える分が切られて比べられます(長いキーの中は取れません)。入れ子は16段まで。
- JSONが不正なら
nil, 理由。頼んだ値が全部見つかっていれば、その後ろが途中で切れていても成功にします。
local r = pico.json_pick(body, {"is_playing", "progress_ms", "item.name", "item.artists.1.name",
"item.duration_ms", "item.album.images#"})
if r then
title = r["item.name"] or ""
artist = r["item.artists.1.name"] or ""
playing = r.is_playing == true
end
pico.sd_json_pick
pico.sd_json_pick(path: string, paths: {string} [, opts: table]) -> values: table, truncated: table | nil
-> nil, error: string
-> nil, error: string
json_pick のSDのファイル版です。pico.http_request の save_to で保存した、16KiBを超える応答を読むのに使います。ファイルは1MiBまで。頼んだ値が全部見つかった時点で残りは読みません。
sd_read と同じく、sd_outside_app_dir 権限が無ければアプリのフォルダの外は読めません(nil, 理由)。