この記事は Nim Advent Calendar 2016 18 日目の記事です。
さて、ネタが被ったような気がしないでもないのですが
nim で json 扱うのが楽ですよって話をします。
json の扱いの簡単さはとても大切ですね。
今回例として使用した json は json.org の JSON Example の一番上のやつです。
http://json.org/example.html
この json を example.json として保存し、使用しています。
Version
Nim Compiler Version 0.15.2 (2016-12-18) [MacOSX: amd64]
json module を使う
json module を使えば json を簡単に扱うことができます
json -> JsonNode
import json when isMainModule: let jsonStr = "example.json".readFile() jsonObj = parseJson jsonStr echo jsonObj["glossary"]["title"].str
- Result
example glossary
JsonNode -> json
import json when isMainModule: let jsonStr = "example.json".readFile() jsonObj = parseJson jsonStr echo $jsonObj
- Result
{"glossary":{"title":"example glossary","GlossDiv":{"title":"S","GlossL...
簡単ですが、用途によってはどこか物足りません。
やっぱり object に詰めて欲しいですよね。
そこで出てくるのが marshal module です。
marshal module を使う
marshal module を使えば json <-> object が実現できます
準備として example.nim として以下を用意しました
type Base = object of RootObj Example* = object of Base glossary*: Glossary Glossary* = object of Base title*: string GlossDiv*: GlossDiv GlossDiv* = object of Base title*: string GlossList*: GlossList GlossList* = object of Base GlossEntry*: GlossEntry GlossEntry* = object of Base ID*: string SortAs*: string GlossTerm*: string Acronym*: string Abbrev*: string GlossDef*: GlossDef GlossSee*: string GlossDef* = object of Base para*: string GlossSeeAlso*: seq[string]
json -> object
import example, marshal when isMainModule: let jsonStr = "example.json".readFile() ex = to[Example] jsonStr echo ex.glossary.title
- Result
example glossary
object -> json
import example, marshal when isMainModule: let ex = Example() echo $$ex
- Result
{"glossary": {"title": null, "GlossDiv": {"title": null, "GlossL...
自分で object に詰める
さきほどの marshal module はとてもシンプルなもので
例えば json の key と object の key を変えたい場合などに対応することはできません。(できなかったはず...)
そのため、json の key に proc などがあるとつらい感じになります。
そういう場合は、自分で object に詰めてしまうのが楽だと思います。
今回の json は string と array しか出てこないので実装はこの程度でした
import json, sequtils proc `[]`(t: JsonNode, key: string): JsonNode = result = if t.hasKey(key): json.`[]`(t, key) else: nil proc to[T: object](node: JsonNode, data: var T) = for k, v in data.fieldPairs: when v is string: v = node[k].getStr elif v is seq: if node[k] == nil: v = @[] else: v = node[k].elems.map(proc(x: JsonNode): string = x.str) else: node[k].to v
- Usage
import example, json, sequtils ... when isMainModule: let jsonStr = "example.json".readFile() jsonObj = parseJson jsonStr var ex: Example jsonObj.to ex echo ex
実装も簡単ですし、依存も減るし、諸々の仕様に柔軟に対応できるので
状況次第では自分で実装してしまうのも悪くないかなと思っています。
それでは。