YAML 1.2 メモ (3) リテラル

YAML に文字列の書き方が 5 種類もあるのは、人間が手打ちするときに便利なように配慮してあるのでしょう。配慮はありがたいのかもしれませんけど、YAML の文字列には、リテラルを除いて必ず Wiki 記法の段落記法に似た行折りたたみ機能が働くため、頭にいれておかないとハマります。リテラルとフォールデッド以外では行の前後の空白もインデント以外のスペースとタブも削られてしまいます。これら含めてコントロールしたいときはリテラルを使うか、ダブル・クォーテッドで行末改行文字をエスケープ・シーケンスで殺して明示的にエスケープ・シーケンスでコントロールするしかありません。

種類 エスケープシーケンス 行折りたたみ 行頭行末スペース チョンピング
リテラル なし なし インデント分のみストリップ
フォールデッド なし 特殊 インデント分のみストリップ
プレイン なし あり 両方ストリップ 指定不可
ダブルクォーテッド あり あり 両方ストリップ 指定不可
シングルクォーテッド ダブルシングルだけ あり 両方ストリップ 指定不可

そのようなわけで、リテラルはヒアドキュメントに近くて使い勝手が良いので、複数行に渡るときはこれを使うに限ります。ヒアドキュメントと違い、末尾改行の chomp の有無を指定することができます。

--- |
リテラルのインディケータは縦棒文字です。
--- |-
縦棒に続いてチョンピング・インディケータのマイナスかプラスを記述します。
マイナス (strip) のときは、リテラル内容直後の改行文字を内容から外します。
内容の後続空行列の改行文字も内容から外します。
--- |+
プラス (keep) のときは、リテラル内容直後の改行文字を内容にとりこみます。
内容の後続空行列の改行文字も内容にとりこみます。
この例では、この後に4つの改行がつきます。



--- |
チョンピング・インディケータを省略すると、リテラル内容直後の改行文字を内容にとりこみ、
内容の後続空行列の改行文字も内容から外します。つまり内容がある場合、最後に改行がつきます。

インデント・インディケータは数字一文字で、メモ (2) の通り、リテラル自身のインデント・レベルからの正の相対値を指定します。ゼロを指定すると内容が空になるのが仕様通りの動作です。インデント・インディケータを省略すると、最初の非空白行の先頭スペースの文字数からリテラル内容のインデント・レベルを自動検出する約束になっています。自動検出の場合でも、リテラル内容のインデント・レベルはリテラル自身のインデント・レベルよりも深くないといけません。

--- |1
リテラル・自身のインデント・レベル(n)はドキュメントのインデント・レベルで -1。
リテラル内容のインデント・レベル(n+m)はゼロ以上で、
ゼロのときのインデント・インディケータ(m)は 1 というのがメモ (2) の内容でした。
--- |


  インデント・インディケータ未指定のとき、最初の非空白行から(n+m)を自動検出します。
  この例では(n+m=2)になり、インデント・インディケータ(m)に 3 を指定したのと同じことになります。
  このリテラルの場合、先頭2行の空白行もリテラルの内容にとりこまれます。
---
|
  気をつけないといけない点は、リテラル・インディケータの前で改行したときです。
  このとき、リテラル自身のインデント・レベル(n)はドキュメントと同じ -1 ですが、
  行頭からリテラル・インディケータまでの間のスペースが(n+1)個以上必要です。
  ドキュメントは -1 なのでゼロ個以上になり、気を使う必要はありませんが、
  ブロック・シーケンス等の場合には、スペースが余計に1個必要なのをつい忘れます。
---
  -
   |
   例えば、この場合、ブロック・シーケンスのインデント・レベルは行頭スペースの数
   になるので 2 です。リテラル自身のインデント・レベルも 2 です。
   ゆえに、リテラル・インディケータの前で改行したとき、スペース 3 個以上必要です。
   つまり、見掛け上、リテラル・インディケータのインデント・レベルは
   リテラル内容の最小インデント・レベルになります。
  -   -
       |
       このコンパクト・シーケンスのインデント・レベルは最初のスペース 2 個に
       シーケンス・インディケータ 1 文字、続くスペース 3 個合わせて 6 です。
       リテラル自身のインデント・レベルも 6 です。
       ゆえに、リテラル・インディケータ前で改行したときは 7 個以上のスペースが必要です。
       リテラル内容のインデント・レベルは 7 以上です。
      -
       |
       単純に考えたいなら、シーケンス・インディケータより1つ以上深くすれば良いのです。
  -
   !!str
   &anchor
   |
   リテラル・インディケータ前で改行したときの行頭スペースの必要数ルールは
   リテラルのプロパティにも摘要されます。
  - !!str &anchor |
   いっそ、改行しないでおく方が、悩まずに済むので良いかもしれません。

リテラルの内容は、リテラル・インディケータのある行の次の行から内容のインデント・レベルを満たす最後の非空白行の改行の直前までです。直後の改行の扱いはチョンピング・インディケータでとりこむか外すか制御できることは既に述べました。その後に空白行を続けることができ、それらの改行文字をとりこむか外すかもチョンピング・インディケータで制御できることも述べました。まぎらわしいのは、空白行だけの場合で、このとき内容は空とみなし、空白行は末尾のチョンピング対象のものとみなします。

---
  - |+ # これは YAML のコメント。リテラルの内容ではありません。
       # これはリテラルの内容で、YAML のコメントではありません。

       # これもリテラルの内容です。
       
       途中の空行もリテラルの内容です。
       途中の空行に含まれるインデント・レベル以上の行頭のスペースとタブも
       内容にとりこみます。
          

       チョンピング・インディケータがプラスなので、次の行の後に改行3つをとりこみます。
       この行の改行の直前までがリテラルの内容です。
       
       
     # この行はインデント・レベルが浅いので YAML のコメントです。

  -
  
  
                |   # リテラル・インディケータの前に空行・空白はいくつでも置けます。


       これもリテラルの内容です。前にある2行の空白行もリテラルの内容にとりこまれます。
       リテラル自身のインデント・レベルはブロック・シーケンスのインデント・レベルで
       決まり、リテラル・インディケータの行のインデント・レベルで決まるわけではありません。




  - |- # これは内容が空のリテラルです。空文字列を生成します。


  # おしまい
...