YAMLはエントリのキーにJSONオブジェクトを使える


JSONに対する簡略表記としての活躍の陰に隠れて、YAMLがマップの各エントリのキーに文字列以外も使えることはあまり知られていない。YAMLは特有のデータ構造を持っており、JSONの従僕ではない。以下は完全に有効1なYAMLファイルの例2である:

- [ YAML: separate ]
- [ : empty key entry ]
- [ {JSON: like}: adjacent ]
- [ [array, as, key]: value ]

もちろん、これをJSONに変換するような用途では、キーをそのままの形にしておくことはできない。例えば有名なNPMパッケージのjs-yamlは、これをJSONにしようとすると暗黙的に無理やり変換しようとするっぽいかもなのです:

[ [ { YAML: 'separate' } ],
  [ { null: 'empty key entry' } ],
  [ { '[object Object]': 'adjacent' } ],
  [ { 'array,as,key': 'value' } ] ]

YAMLには canonical format と呼ばれる記法があり、その名の通り正式な形式のことである。これがYAMLのデータ構造の本質を表していると考えるといい。最初の例をそれで表記すると以下のようになる:

%YAML 1.2
---
!!seq [
  !!seq [
    !!map {
      ? !!str "YAML"
      : !!str "separate"
    },
  ],
  !!seq [
    !!map {
      ? !!null
      : !!str "empty key entry"
    },
  ],
  !!seq [
    !!map {
      ? !!map {
        ? !!str "JSON"
        : !!str "like"
      }
      : !!str "adjacent",
    },
  ],
  !!seq [
    !!map {
      ? !!seq [
        !!str "array",
        !!str "as",
        !!str "key",
      ]
      : !!str "value",
    },
  ],
]

使い道

キーに文字列以外を使うようなやり方はかなり黒いので、普通は避けるだろう。しかしとてつもなく格好がつく場合もある。例えば音韻論では音声をブラケットで囲んで表記することがある。JSONでは以下のように書かなければならないデータを:

{
  "基本子音": {
    "/i/": {
      "[ç̞ˡ]": "下寄り無声硬口蓋側面摩擦音"
    },
    "/q/": {
      "[ɋ͢ʩ]": "無声口蓋帆破擦音",
      "[ɋ͢ƨ]": "無声口蓋帆破裂音からの無声鼻孔摩擦音"
    }
  }
}

YAMLでは以下のように書けるということだ。

基本子音:
  /i/:
    [ç̞ˡ]: 下寄り無声硬口蓋側面摩擦音
  /q/:
    [ɋ͢ʩ]: 無声口蓋帆破擦音
    [ɋ͢ƨ]: 無声口蓋帆破裂音からの無声鼻孔摩擦音

えへへ。


  1. YAML 1.2 に基づく。マップの文法のBNFルールから辿っていくと、c-flow-json-contentというルールに突き当たる。 

  2. 仕様にある例をやや改変した。