以下のJSONをparseすることを考えます。
json_test.res
let cotoha_result = (`
{
"result": [
{
"chunk_info": {"id": 0, "links": []},
"tokens": [{"form": "公園"}, {"form": "から"}, {"form": "、"}]
},
{
"chunk_info": {"id": 1, "links": []},
"tokens": [{"form": "望遠鏡"}, {"form": "で"}]
},
{
"chunk_info": {"id": 2, "links": []},
"tokens": [{"form": "星"}, {"form": "を"}]
},
{
"chunk_info": {"id": 3, "links": [{"link": 1, "label": "implement"}, {"link": 2, "label": "object"}]},
"tokens": [{"form": "見"}, {"form": "て"}, {"form": "い"}, {"form": "る"}]
},
{
"chunk_info": {"id": 4, "links": [{"link": 3, "label": "adjectivals"}]},
"tokens": [{"form": "女の子"}, {"form": "を"}]
},
{
"chunk_info": {"id": 5, "links": [{"link": 0, "label": "source"}, {"link": 4, "label": "object"}]},
"tokens": [{"form": "見"}, {"form": "た"}]
}
]
}
`)
json_test.res
@scope("JSON") @val external parse: string => result = "parse"
こうすれば良いはずです。1
問題は、result
の型定義をどうするかです。
JSONをみていくと"result": 無名配列
なので、この無名配列をarray<chunk>
とします。
json_test.res
type result = { result: array<chunk> }
chunk
は{"chunk_info": レコード, "tokens": 無名配列}
なので、レコードをchunk_info
型とし、無名配列をarray<token>
にします。
json_test.res
type chunk = { chunk_info: chunk_info, tokens: array<token> }
chunk_info
は{"id": int, "links": 無名配列}
なので、この無名配列をarray<link>
にします。
json_test.res
type chunk_info = { id: int, links: array<link>}
link
は{"link": int, "label":string}
です。
json_test.res
type link = { link: int, label: string }
残りはtoken
で{"form": string}
です。
json_test.res
type token = { form: string }
これで必要な型が定義できました。
事前に定義されていない型は、型宣言で利用できないので、末端から根に向けて宣言する感じになります。
json_test.res
type token = { form: string }
type link = { link: int, label: string }
type chunk_info = { id: int, links: array<link>}
type chunk = { chunk_info: chunk_info, tokens: array<token> }
type result = { result: array<chunk> }
@scope("JSON") @val external parse: string => result = "parse"
json_test.res
let result = parse(cotoha_result)
Console.log((result.result->Array.getUnsafe(0)).chunk_info.id)
Console.log(((result.result->Array.getUnsafe(1)).tokens->Array.getUnsafe(0)).form)
パースされ、色んな値にアクセスできるようになっています。
ReScriptでは配列に添字でアクセスするとoption<'a>
が返ります。
option
の処理を一つずつ書くと煩雑になるので、Array.getUnsafe
を用いました。
複雑なJSONを型定義することになったら超大変な気がします。
そもそも型付き言語でJSON使ってるのがどうなのかという話なのかも知れません。