はじめに
最近、ansibelなどの設定書式で用いられる記法「YAML」について、紹介します。 YAMLは、箇条書きのように記載できるため、大変わかりやすいフォーマットです。
YAMLとは?
概要
YAML Ain’t Markup Languageの略で、構造化データの表現する記法になります。 主に以下のような用途で利用されます。
- 設定ファイル
- データ保存
- データ交換
XMLとの違い
XML = 開始、終了タグ(
XMLと比べ、人が見る場合に非常にわかりやすい構造で表現することが可能となります。
以下、XMLとYAMLを比較すために、サンプルを記載します。
例) 書籍の一覧を表現する場合
[XML]
<books> <book> <name>書籍タイトルその1</name> <author>山本 太郎</author> </book> <book> <name>書籍タイトルその2</name> <author>鈴木 一郎</author> </book> </books>
[YAML]
books: - name:書籍タイトルその1 author:山本 太郎 - name:書籍タイトルその2 author:鈴木 一郎
公式サイト
YAMLの公式サイトは、以下になります。書式の仕様などを調べる際にお役立てください。
URL http://yaml.org
環境
今回は、YAMLを構文を確認するため、Pythonを利用します。 各バージョンは、以下のとおりです。
□ OS
[root@yaml ~]# cat /etc/redhat-release CentOS release 6.6 (Final)
□ YAML
[root@yaml ~]# rpm -aq |grep yaml libyaml-0.1.6-1.el6.x86_64 libyaml-devel-0.1.6-1.el6.i686
□ Python
[root@yaml ~]# python -V Python 2.6.6
※補足
今回は、YAMLファイルとPythonを繋ぐライブラリはAnsibleで利用されている「LibYAML for Python」を使います。
項目 | 説明 |
---|---|
ライブラリ名 | LibYAML for Python |
WEBサイト | http://pyyaml.org/wiki/PyYAML |
ドキュメント | http://pyyaml.org/wiki/LibYAML |
ダウンロード | http://pyyaml.org/download/libyaml |
バージョン | 0.1.6 |
YAML対応 | YAML 1.1準拠 |
YAMLを触ってみる。
まず、YAMLの構文に慣れてもらうため、簡単なプログラムを書いてみます。
MyYaml.ymlの作成
YAMLを記述するファイルを作成します。 拡張子は、「yml」になります。
ここでは、配列を表す記述を記載してみます。
[root@yaml ~]# vi MyYaml.yml [root@yaml ~]# cat MyYaml.yml - a - b - c
parse.pyの作成
記載したYAMLファイルの構文をチェックするため、Pythonのコードを記述するファイルを作成します。 拡張子は、「py」になります。 ※parseとは、構文に従って分析する、品詞を記述する、構文解析するなどの意味を持つ単語です。
[root@yaml ~]# vi parse.py [root@yaml ~]# cat parse.py #-*- coding: utf-8 -*- # yamlを利用するための宣言 import yaml; # MyYaml.ymlファイルを読み込み(パース)後、結果を標準出力。 print yaml.load(open('MyYaml.yml').read())
動作確認
作成したMyYaml.ymlを、parse.pyでパースして、出力結果を確認します。
[root@yaml ~]# python parse.py ['a', 'b', 'c']
以降の章からは、「MyYaml.yml」へ記載内容と「python parse.py」を実行した結果のみを記述して、YAMLファイルの書き方を覚えていきます。
XXXXXXX # MyYaml.ymlの編集内容記載 (結果) [XXXXXXX] # python parse.pyを実行した結果記載
基本的な構文を抑えよう。
YAML では、主に次の 3 つの組み合わせでデータを表現します。
スカラー(scalar) 文字列、数値、真偽値などの変数(値の入れ物)を表す。 YAMLで記述した値は、自動的にデータ型を判別する。 ※Javaのようなデータ型の宣言は必要なく、中間のライブラリ(JYaml)が自動的に判別し、値を渡してくれます。
ここでは、上記の3つの書き方を紹介します。
シーケンス(Sequence)
□ 基本書式
- d1 - d2 - d3 (結果) ['d1', 'd2', 'd3']
☆注意点☆
- [-]の後の半角スペースは必須。
- d1 -d2 #半角スペースなし - d3 (結果) Traceback (most recent call last): File "parse.py", line 6, in~ 略 ~
□ 入れ子(ネスト)書式
- d1 - - sd2-1 - sb2-2 - d3 (結果) ['d1', ['d2-1', 'd2-2'], 'd3']
☆注意点☆
- 字下げにタブ・全角空白は使えない。※半角スペース2つで記述。
- d1 - - sd2-1 # 字下げにタブ使用。 - sb2-2 - d3 (結果)※エラーが発生。 Traceback (most recent call last): File "parse.py", line 6, in~ 略 ~
- 入れ子の際、親の値は記載しない。
- d1 - d2 # 親値を記載 - sd2-1 - sb2-2 - d3 (結果) ※入れ子にならず、1つ配列として認識される。 ['d1', 'd2 - sd2-1 - sd2-2', 'd3']
マッピング(Mapping)
□ 基本書式
key1: val1 key2: val2 (結果) {'key2': 'val2', 'key1': 'val1'}
☆注意点☆
- :(コロン)の後の半角スペースは必須(1つ以上)。
key1: val1 key2:val2 # 半角スペースなし (結果)※エラーが発生。 Traceback (most recent call last): File "parse.py", line 6, in~ 略 ~
- key:の「:(コロン)」の前に半角スペースを入れることも可。 ** インデントを揃えることが出来る。
hostname: nsw1.exzample.com ipv4 : 192.168.0.1 # ipv4の後に半角スペースを入れる (結果) {'hostname': 'nsw1.exzample.com', 'ipv4': '192.168.0.1'}
□ 入れ子(ネスト)書式
keys: skey1: val1 skey2: val2 (結果) {'keys': {'skey1': 'val1', 'skey2': 'val2'}}
☆注意点☆
- 字下げにタブは使えない。半角スペース2つで記述。
keys: skey1: val1 skey2: val2 #字下げにタブ使用。 (結果)※エラーが発生。 Traceback (most recent call last): File "parse.py", line 6, in~ 略 ~
- 入れ子の際、親の値は記載しない。
keys: vals # 親値を記載 skey1: val1 skey2: val2 (結果)※エラーが発生。 Traceback (most recent call last): File "parse.py", line 6, in~ 略 ~
スカラー(scalar)
□ 自動判別
- 記載した値が自動的に判別されることを確認します。
# 文字列 str1: 文字列 str2: string # 整数 decimal1: 123 # 10 進数 decimal2: 1,234,567,890 # 10 進数 octal: 0644 # 8 進数 hexa: 0xFF # 16 進数 # 浮動小数点 float1: 0.05 # 真偽値 (true, yes, false, no) bool1: true # 真 bool2: yes # 真 bool3: on # 真 bool4: false # 偽 bool5: no # 偽 bool6: off # 偽 # Null値 (null, ~) null1: ~ null2: null # 日付 (yyyy-mm-dd) date: 2005-01-01 # タイムスタンプ (yyyy-mm-dd hh:mm:ss [+-]hh:mm) stamp: 2005-01-01 00:00:00 +09:00 (結果) {'date': datetime.date(2005, 1, 1), 'float1': 0.050000000000000003, 'bool5': False, 'bool4': False, 'bool6': False, 'bool1': True, 'bool3': True, 'bool2': True, 'hexa': 255, 'str2': 'string', 'str1': u'\u6587\u5b57\u5217', 'decimal2': '1,234,567,890', 'stamp': datetime.datetime(2004, 12, 31, 15, 0), 'null1': None, 'octal': 420, 'null2': None, 'decimal1': 123}
□ 文字列変換
文字列として変換したい場合は、「"“」(ダブルコーテーション)で囲みます。
# 整数 decimal1: 123 # 10 進数 decimal2: 1,234,567,890 # 10 進数 octal: 0644 # 8 進数 hexa: 0xFF # 16 進数 # 整数 decimal1: "123" # 10 進数 decimal2: "1,234,567,890" # 10 進数 octal: "0644" # 8 進数 hexa: "0xFF" # 16 進数 # 浮動小数点 float1: "0.05" # 真偽値 (true, yes, false, no) bool1: "true" # 真 bool2: "yes" # 真 bool3: "on" # 真 bool4: "false" # 偽 bool5: "no" # 偽 bool6: "off" # 偽 # Null値 (null, ~) null1: "~" null2: "null" # 日付 (yyyy-mm-dd) date: "2005-01-01" # タイムスタンプ (yyyy-mm-dd hh:mm:ss [+-]hh:mm) stamp: "2005-01-01 00:00:00 +09:00" (結果) {'bool5': 'no', 'bool4': 'false', 'bool6': 'off', 'bool1': 'true', 'bool3': 'on', 'bool2': 'yes', 'hexa': '0xFF', 'null1': '~', 'null2': 'null', 'decimal2': '1,234,567,890', 'octal': '0644', 'date': '2005-01-01', 'float1': '0.05', 'decimal1': '123', 'stamp': '2005-01-01 00:00:00 +09:00'} ※文字列変換前 {'bool5': False, 'bool4': False, 'bool6': False, 'bool1': True, 'bool3': True, 'bool2': True, 'hexa': 255, 'null1': None, 'null2': None, 'decimal2': '1,234,567,890', 'octal': 420, 'date': datetime.date(2005, 1, 1),'float1': 0.050000000000000003, 'decimal1': 123, 'stamp': datetime.datetime(2004, 12, 31, 15, 0)}
複雑な構文を抑えよう。
前章では、基本的な構文を紹介しました。 ここでは、シーケンスとマッピングを混合した書き方を紹介します。
マッピング - シーケンス
□ 基本書式
- bookname: sample1 author: taro - bookname: sample2 author: jiro (結果) [{'bookname': 'sample1', 'author': 'taro'}, {'bookname': 'sample2', 'author': 'jiro'}]
シーケンス - マッピング
□ 基本書式
books: - sample1 - sample2 authors: - taro - jiro (結果) {'books': ['sample1', 'sample2'], 'authors': ['taro', 'jiro']}
ブロックスタイルとフロースタイルを抑える。
YAMLの構文には、以下の2種類があります。
ブロックスタイル インデントを使って構造を表す書き方 1 行に収まる文字列の場合に便利。
フロースタイル 「{}」や「[]」を使って構造を表す書き方 複数行にわたる文字列の場合に便利。
今まで紹介した構造の書き方は、「 ブロックスタイル 」になります。 以降は、「 フロースタイル 」に構造の書換え、その違いを確認しましょう。
シーケンス(Sequence)
□ 基本書式
[d1, d2, d3] (結果) ['d1', 'd2', 'd3']
☆注意点☆
- [,]の後の半角スペースは必須。
[d1,d2, d3] #d2の前の半角スペースなし (結果)※エラーが発生。 Traceback (most recent call last): File "parse.py", line 6, in~ 略 ~
□ 入れ子(ネスト)書式
ネストしたい個所を[]で囲みます。
[d1, [d2-1, d2-2], d3] (結果) ['d1', ['d2-1', 'd2-2'], 'd3']
マッピング(Mapping)
□ 基本書式
{key1: val1, key2: val2} (結果) {'key2': 'val2', 'key1': 'val1'}
☆注意点☆
{key1: val1,key2:val2} # key2前の半角スペースなし (結果)※エラーが発生。 Traceback (most recent call last): File "parse.py", line 6, in~ 略 ~
□ 入れ子(ネスト)書式
{keys: {skey1: val1, skey2: val2}} (結果) {'keys': {'skey1': 'val1', 'skey2': 'val2'}}
マッピング - シーケンス
□ 基本書式
[ {bookname: sample1, author: taro}, {bookname: sample2, author: jiro} ] (結果) [{'bookname': 'sample1', 'author': 'taro'}, {'bookname': 'sample2', 'author': 'jiro'}]
シーケンス - マッピング
□ 基本書式
{ books: [sample1, sample2], authors: [taro, jiro] } (結果) {'books': ['sample1', 'sample2'], 'authors': ['taro', 'jiro']}
改行を含むデータを扱ってみよう
YAMLの特性として改行すると次のデータになってしまいます。 改行を利用する場合は、下記の記号を利用します。
|(パイプ) ** 改行を保存することが可能。
(リダイレクト) ** 半角スペースに置き換える事が可能。
|(パイプ)を利用してみる。
key: | v a l (結果) {'key': 'v\na\nl\n'} #改行コード「\n」が保存されます。
>(リダイレクト)を利用してみる。
key: > v a l (結果) {'key': 'v a l'} #改行コードが半角スペースに変換されます。
まとめ
もう、お分かりの通り
%{color: red; font-size: 20px;}YAML% では、 %{color: red; font-size: 20px;}インデント% が %{color: red; font-size: 20px;}重要% です。
途中でも紹介しましたが、YAMLファイルを作成する場合は、次の注意点は覚えておきましょう!!
- 「-(ハイフン)」,「:(コロン)」,「,(カンマ)」の後には、1文字以上の半角スペースを入れること。
- タブや全角スペースによるインデントは禁止。
おわりに…
今回は、Ansibleの構文を書くために必要な知識を覚えて頂くことを目的としたため、紹介しませんでしたが、他にもYAMLでは、次のようなことも出来ます。 ※Ptyhon(LibYAML for Python)で対応していない物もあり。
- アンカー(&)とエイリアス() ** アンカー(&)で記載した構文を、エイリアス()で複製する。
- …(ピリオド3つ) ** 指定した以降の処理は、スキップする。
- —(ハイフン3つ) ** ドキュメントの終始を表す。
etc…
これらの情報は、以下のサイト(Ruby + YAML)がまとまっておりました。
http://magazine.rubyist.net/?0009-YAML
良ければ、ご参照ください。