どんな事でもお気軽にお問い合わせください
0120-803-656
24時間受付いたします

JSON と何が違う?ってところから始める YAML 入門


こんにちは。
開発チームのワイルド担当、まんだいです。

JSON というデータフォーマットが世に広まって久しい昨今ですが、同じようなデータフォーマットとして YAML というものがあります。
普段使うプログラム言語によって、 JSON をよく使うか YAML をよく使うか変わってくると思います。
API 開発をしていると、外部とのやり取りはほとんど JSON ですし、フロントエンド開発やバックエンドでも PHP を主として扱っている場合、組み込み関数で一発変換できる JSON でやり取りすることがほとんどかと思いますし、なかなか YAML に触れる機会がないのも事実です。

今回は知ってしまえば何てことはない、 YAML についてまとめてみます。

 

YAML について

YAML という言葉と似ているものを、皆さんはご存知だと思います。
HTML はかなり似ていますし、 XML なんかも似ているかと思います。

それもそのはず、 YAML の正式名称は「 YAML Ain't a Markup Language 」で、 TYAML マークアップ言語ではないよと言ってしまっている、いわゆるバクロニムになっています。

マークアップ言語ではなく、データフォーマットという認識は間違っていなかったわけですね。

 

【基礎編】扱えるデータ型

YAML が扱えるデータ型は3つだけです。

  • シーケンス
  • マップ(マッピング)
  • スカラー

この3つの型だけでデータを表すというのですから、割と取っ付き易いと思いませんか?
これに表現の幅を持たせる各種の記号を組み合わせて、様々なデータを表していく訳です。

それぞれのデータ型について、詳しく見ていきましょう。

 

シーケンス型

シーケンスは連続した数字の添字を持つ配列のことを指します。
キーという概念は存在しないので、シンプルに複数の値を持たせる場合に利用します。

- abc
- def
- 123

 

ハイフンで始まり半角スペースを入れた後、データを入力します。
上記のYAMLデータを JSON に変換すると、以下の形になります。

["abc", "def", 123]

 

マップ型

マップは添字を指定できる配列(連想配列)を指します。
キーと値が対になっていて、値にはスカラー、シーケンス、マップを取ることができるため、構造が複雑になりやすい側面もあります。

aaa: test1
bbb: test2
ccc: test3
ddd:
  eee: test4
  fff: test5

 

上記の例では、ddd をキーに持つ値がマップになっていて、ネストされている状態です。
こちらを JSON に変換すると、以下の形になります。

{"abc": "test1", "bbb": "test2", "ccc": "test3", "ddd": {"eee": "test4", "fff": "test5"}}

 

さらに見やすいようにフォーマットすると以下のようになります。

{
    "abc": "test1",
    "bbb": "test2",
    "ccc": "test3",
    "ddd": {
        "eee": "test4",
        "fff": "test5"
    }
}

 

さらにさらに、先に出たシーケンス型と組み合わせて、並び順を指定したマップ型 (Ordered Mapping) という形もあります。

- aaa: test1
- ccc: test2
- bbb: test3

 

キーの並び順が重要な場合、シーケンスっぽく並び順を指定しつつマップっぽくキーを付けるという組み合わせができます。
この概念は JSON にはない概念ですね。

 

スカラー型

最後はスカラーです。
スカラーは数値や文字列、ブール値など、簡単に言うと単一の値を指します。
マップ型、シーケンス型で既に出てきていますが、どのような値がスカラーになるかというと、マップ、シーケンス以外のデータ型全てがスカラー型とされています。

マップ型とシーケンス型は、データの型というより構造を表すものなので、実際にどのような値かを定義しているのはスカラー型とも言えますね。

スカラー型は単独では書けないため、シーケンス型の要素として表現してみます。

- 100                                       # number (10進数)
- 016                                       # number (8進数)
- 0xAC                                      # number (16進数)
- 3.14                                      # number (float)
- 12.3e+4                                   # number (指数)
- .inf                                      # number (+方向の無限大)
- -.inf                                     # number (-方向の無限大)
- true                                      # bool
- false                                     # bool
- on                                        # bool
- off                                       # bool
- yes                                       # bool
- no                                        # bool
- null                                      # null
- ~                                         # null
- test                                      # string
- 1980/09/02                                # string (注意)
- 1980-09-02 00:00:00.000-09:00             # datetime (ISO-8601 format)
- 1980-09-02                                # date (year, month, day)
- 1980                                      # date (year)

 

この中で、文字列だけが、改行を含めた複数行のデータを持ち得るので、複数行のテキストデータを表現するためにいくつかのおまじないが用意されています。

# シンプルな改行を含めたテキスト
test1: |
  改行を含めたテキストが書けます。
  改行を含めたテキストが書けます。

 

# 改行を半角スペースに置換する (データを取り出した時点では改行コードは存在しないことになる)
test2: >
  改行を含めたテキストが書けます。
  改行を含めたテキストが書けます。

 

いずれのパターンでも、各行頭に存在するインデント用の半角スペースは除去されます。
「>」の場合、除去した後、改行を半角スペースに置換することになっています。

また、上の2つに「+」と「-」を組み合わせることで、最終行の改行を含むか取り除くかを定義できます。

# 最終行の行末に改行コードを付ける
test3: |+
  改行を含めたテキストが書けます。
  改行を含めたテキストが書けます。

 

# 最終行の行末に改行コードを付けない
test4: |-
  改行を含めたテキストが書けます。
  改行を含めたテキストが書けます。

 

# 最終行の行末に改行コードを付ける (ただし、文中の改行については除去する)
test3: >+
  改行を含めたテキストが書けます。
  改行を含めたテキストが書けます。

 

# 最終行の行末に改行コードを付けない
test4: >-
  改行を含めたテキストが書けます。
  改行を含めたテキストが書けます。

 

テキストの内容によっては、インデントに使っているスペースを除去されると困る場合もあります。
そんな時に各行頭にスペースをいくつ入れるかを指定することもできます。

# 各行頭に2つのスペースを入れる
test1: |2
  改行を含めたテキストが書けます。
  改行を含めたテキストが書けます。

 

# 各行頭に4つのスペースを入れる
test1: |4
    改行を含めたテキストが書けます。
    改行を含めたテキストが書けます。

 

行頭にいくつスペースを入れるかとインデントの数には微妙な関係があって、指定した数以上のスペースがインデントに存在する場合はOKですが、少ない場合はフォーマット上間違っていることになるようです。

# 各行頭に4つ以上スペースが必要なのでエラー
test1: |4
  改行を含めたテキストが書けます。
  改行を含めたテキストが書けます。

 

また YAML の定義では、行頭に挿入するスペースの数で指定できるのは、 1 <= n <= 9 の範囲のようです。  

ネストについて

既に何度か登場していますが、マップとシーケンスに関しては要素をネストすることができるため、インデントでネストを表現することができます。
YAML では、インデントはスペース2つを1つのインデントとみなします。

# シーケンス同士のネスト
- aaa
- bbb
- ccc
  - ddd
  - eee
  - fff

 

# マップ同士のネスト
aaa: test1
bbb: test2
ccc:
  ddd: test3
  eee: test4
  fff: test5

 

# シーケンスとマップのネスト
- aaa
- bbb
- ccc
  ddd: test1
  eee: test2
  fff: test3

 

# マップとシーケンスのネスト
aaa: test1
bbb: test2
ccc:
  - ddd
  - eee
  - fff

 

# 順序ありマップのネスト (インデントの数に注意)
- aaa: test1
- ccc: test2
- bbb:
    - ddd
    - eee
    - fff

 

順序ありマップの子要素にマップもしくはシーケンスが来る場合、インデントを2つ分(スペース4つ)付けないと正しくネストできていないようです。

 

Visual Studio Code で YAML を扱う場合は

Visual Studio Code(以下、VSCode)で YAML を扱う場合、標準でもある程度対応している機能があるため扱いやすくはあります。
しかし、更に便利な環境を作るには、拡張機能が必要だと感じています。

Red Hat が公開しているその名もズバリ YAML という拡張機能を使えば、コードヒントやバリデーションが効く環境がサッと用意できるため、非常にオススメです。
Language Server を使った本格的な拡張機能になっていて、使い心地も良好です。
外部スキーマにも対応しているため、 API 開発ではよく使用する Swagger の YAML 用のスキーマデータを読み込むとか、AWS の CloudFormation 用の スキーマデータ、 docker-compose.yml 用のスキーマデータなど、定義済みスキーマを読み込むこともできるため、より使いやすくすることができます。

Kubernetes 用の YAML スキーマは同梱されているため、特に用意する必要はありません。

 

まとめ

今回は YAML について小ネタも混ぜつつ入門編記事を書いてみましたが、いかがだったでしょうか?
YAML って難しい!と思っていた方も、実は基本的なデータ型は3つしかないということを知らずに敬遠されていた方もおられるんじゃないかなと思います。

スカラー型には組み込みのデータ型がいくつかあって、見た目上はどれも文字列なんですが、YAML 的にはそれぞれのデータ型をきちんと見分けているんだということもわかったのではないでしょうか。
文字列に関しては、複数行の文字列の表現方法としていくつか便利な書き方がありますので、例を見ながらその時々にあった表現方法を使いたいところです。

マップとシーケンス、またそれらを合わせた順序ありマップ(なにかいい名前がほしい)でデータ構造を自由に表現して、見通しの良いデータ定義ができればメンテナンスしやすいコードになること間違いなしです。

実は、アンカーやエイリアスといったデータ定義を別の場所に書く方法や、複数のデータ構造を一つにファイルの中に書いてしまう方法など、応用編的な利用法についてはご紹介しきれなかったので、別の機会を設けてご紹介しようと思っていますので、お楽しみに!

 
以上です。


お問い合わせ 採用情報 エンジニアブログ
ISO27001認証
Contact PageTop
株式会社ビヨンド

© beyond Co., Ltd. All rights reserved.