Go で JSON5 データを読み込む

3 min読了の目安(約2800字TECH技術記事

いつものように小ネタです。

JSON (JavaScript Object Notation) はデータ交換用のテキストフォーマットとしてはシンプルで非常に優れているのだが,人間側から見て読み/書きやすいかというと微妙だったりする。

その辺の不満を解消しようというのが JSON5 である。

JSON5 の特徴は以下の通り(「知らないうちにJSON5 in Babel - Qiita」からの引用)

  • オブジェクト
    • キーは一重引用符でも、識別子として使えるものならOK
    • ケツカンマOK
  • 配列
    • ケツカンマOK
  • 文字列
    • 一重引用符もOK
    • 文字列の途中で(バックスラッシュでエスケープすれば)改行OK
    • \x0fのようなエスケープシーケンスを使える
  • 数値
    • 0xabcdのような16進法でもOK
    • 16..23のような、小数点前後の片方だけ書くのもOK
    • +12のようなプラス記号も使える
    • InfinityNaNも値として受け付ける
  • コメント
    • /* ... */あるいは// (このあと行末まで) といったコメントを使える

例えばこんな感じの記述ができる(オフィシャル・サイトより)。

json5-sample.json5
{
  // comments
  unquoted: 'and you can quote me on that',
  singleQuotes: 'I can use "double quotes" here',
  lineBreaks: "Look, Mom! \
No \\n's!",
  hexadecimal: 0xdecaf,
  leadingDecimalPoint: .8675309, andTrailing: 8675309.,
  positiveSign: +1,
  trailingComma: 'in objects', andIn: ['arrays',],
  "backwardsCompatible": "with JSON",
}

しかし,逆に既存のツール等で JSON5 テキストを読み込ませるのは難しかったりする。たとえば事実上の標準である jq に読み込ませようとしても

$ cat json5-sample.json5 | jq .
parse error: Invalid numeric literal at line 2, column 5

てな具合に最初の1フィートでぶっコケる。

オフィシャルのリポジトリを見ると少なくとも node.js 用のパーサはあるようだが,残念なことに Go 用のパッケージは Archive 化されていて使いものにならないようだ。

で,どなたか Go 用の JSON5 パーサ作ってないかなぁ,と軽くググってみたら,以下のパッケージがよさげである。

JSON5 テキストの Decode (または Unmarshal) が標準の encoding/json と互換になっていて,パッケージ名を json5 に置き換えれば済みそうだ。

こんな感じ。

sample.go
package main

import (
    "encoding/json"
    "fmt"
    "os"

    "github.com/flynn/json5"
)

func main() {
    elms := make(map[string]interface{})
    if err := json5.NewDecoder(os.Stdin).Decode(&elms); err != nil {
        fmt.Fprintln(os.Stderr, err)
        return
    }
    if err := json.NewEncoder(os.Stdout).Encode(elms); err != nil {
        fmt.Fprintln(os.Stderr, err)
    }
}

これを使えば

$ cat json5-sample.json5 | go run sample.go | jq .
{
  "andIn": [
    "arrays"
  ],
  "andTrailing": 8675309,
  "backwardsCompatible": "with JSON",
  "hexadecimal": 912559,
  "leadingDecimalPoint": 0.8675309,
  "lineBreaks": "Look, Mom! No \\n's!",
  "positiveSign": 1,
  "singleQuotes": "I can use \"double quotes\" here",
  "trailingComma": "in objects",
  "unquoted": "and you can quote me on that"
}

といい感じに JSON に変換できる。

4年前に更新されたきりでモジュールにも対応していないのだが,まぁ鼻の先は問題ないだろう。