Yaml を利用して C# でヒアドキュメントを考える

XAML + XDocument + XamlReader.Load を使うと、ヒアドキュメントっぽくコードに XAML を書くことができます。

[WinRT] XElement を使い XAML を構築して動的に XamlReader.Load で読み込む技 | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/6556

な感じで、XElement を使って構築してもよいし、文字列で XAML を書いてもよい(実際 Storyboard のクローンを作るときは、そうしています)。VB であれば XML 構文を使えばよいのです。
が、ヒアドキュメントで書くにせよ、外部ファイルの読み込み(あるいはリソースからの読み込み)であっても、XML を手書きするのがちょっと面倒で、特に「閉じタグ」の問題が関わってきてしまいます。Visual Studio 付属の XML エディタを使って作ればよい(単純に拡張子を .xml にするだけ)なものの、できれば「閉じタグ」なしで書いていきたい。

XElement の羅列のほうも、閉じタグではないですが、閉じ括弧「)」が頻発します。適切なインデントを付ければ間違いは少ないのですが、そもそもが適切なインデントが付いているはずなので、閉じ括弧はいらないはずです。

Yaml には閉じタグがない

YAMLAin’t Markup Language (YAML) Version 1.2
http://www.yaml.org/spec/1.2/spec.html
C#でYAMLを使えるか試してみた | OPC Diary
http://opcdiary.net/?p=25878
NuGet Gallery | FsYaml 1.1.3
https://www.nuget.org/packages/FsYaml/
閉じタグを超えた先に僕が見た景色とは
http://www.slideshare.net/muyuu/ss-40425076

最後のものは Yaml ではありませんが、Jade という Yaml と似た構文で HTML タグを生成するフレームワークです。

Jade について。
https://gist.github.com/japboy/5402844

を見ると Haml という軽量 HTML 構文から影響を受けているそうなので、Yaml とは潮流が違うみたいですが、

  • インデントを利用して記述する
  • 閉じタグ/括弧が必要ない

ってところで同じでしょう。Yaml 自体は、SPEC で v1.0 以前から見知っていたのですが、Ruby の設定以外にあまり見たことが無くて、それならば XML でも十分ではないか?と思っていたのですよ。ですが、ExDoc を使って検索をしてみると、C# でヒアドキュメントの可能性が出てくるので、そうなると XML 自体の冗長性がちょっと問題になってくるという話です。

Yaml 自体は、YamlDotNet を使うと手軽に読み込めます。取り出しが KeyValue になっているので、今一つ取り出しが面倒ですが、「C#でYAMLを~」の記事のように既存のクラスにマッピングしてから使うのが定番でしょう。ファイル読み込みになっていますが、StringReader を使えば文字列として読み込めるので、コード内のヒアドキュメントとして利用できます。

以下は思考実験です。

Yaml を XML にマッピングする

改めて、Yaml の仕様を見直していたのですが、Yaml にはハッシュとリストしかありません。そういう意味は、XML に属性と値しかないのと似ていて非常にシンプルです。まあ、実際は SPEC を見るとえらい複雑なんですが、まだ v1.0 以前のころはもっとシンプルだったような気が。

とはいえ、適当に XML にマッピングしてみます。XML にマッピングするのは ExDoc で使いやすいのと、他のデータのコンバートしやすいからですね。おそらく JSON からのマッピングも同じになると思います。

Root:
 - person:
   name: masuda
   Age: 46

 

<root>
  <person name='Masuda' age='46' />
</root>

Yaml にはルートは必要ありませんが、仮にルートを決めます。複数並べることがある person タグの場合はリストに、重複しない場合はハッシュで書く、というルールを決めておきます。
上の Yaml から期待されるのは、こんな風に person に属性値で設定された XML ですよね、おそらく。ただし、データとしては属性値であろうと要素の値であろうとどちらでもよいので、

<root>
  <person>
    <name>masuda</name>
    <age>46</age>
  </person>
</root>

こんな感じですべてを要素にするのも可能ですよね。ExDoc の場合は、/ や * 演算子を使うか、% 演算子を使うかという違いが出てきてしまうので、出力される XML は区別されてしまいますが。

先の場合は、person 要素自体が値を持たないので、属性値で要素の値でも似た感じになるのですが、person 要素に値を持たせるようにすると、こんな感じになります。

Root:
 - person: masuda tomoaki
   ID: 100
   Age: 46

person に続くハッシュ値は属性になるというルールを作って、person の属性に設定します。

<root>
  <person ID='100' age='46'>
    Masuda tomoaki
  </person>
</root>

実は、要素だけを使って下記のように作れるのですがあまりお勧めできません。というのも、person の要素を .Value で取れるようにしているのは XElement や ExElement のシンタックスシュガーなところがあって、本来は Text 要素として取ることになります。そうすると、ID タグの後ろとか、age タグの後ろにテキストが入っている場合も探索の対象になって、あまいな部分が多くなります。これは HTML 記法では普通に出てくるものなのですが、ヒアドキュメント的に使いたい場合はこの曖昧さは避けておきたいかなと。

<root>
  <person>
    masuda tomoaki
    <ID>100</ID>
    <age>46</age>
  </person>
</root>

上記の場合、person がリストになっていますが、あえてハッシュの場合も考えてみます。

Root:
  person: masuda tomoaki
    ID: 100
    Age: 46

Root のハッシュとして person を付けます。更に person のハッシュとして ID と Age がある構造ですね。
Yaml ではハッシュの値がハッシュ、ということができるのですが、XML の場合は属性の中に要素を入れることができません。なので、Root のハッシュがさらに子要素を持つような場合には、属性から要素に昇格するという手順が必要そうです。

<root>
  <person ID='100' age='46'>
    Masuda tomoaki
  </person>
</root>

この手順がイリーガルなので Yaml をヒアドキュメントするときに躓きそうな気もするのですが。まあ、子要素は一般的にリスト「-」を使う、というローカルルールにしておけば問題ないかと思います。もともと、ここでの XML の変換自体がローカルルールですから。

Yaml の文章構造をマッピングする

実は Haml という HTML 軽量構文があるので、あまり詳しく作っても仕方がないのですが、ちょっとした RTF っぽい記述をコード内に書き下すことを想定してみます。

HTML:
 Head:
  Title: yaml page
 Body:
  H1: yaml to XML を作る
  P:
    ここに文章を書き下す。

こんな風に Yaml で書いておいてコンバートすると、XHTML(のようなもの)を吐き出します。

<html>
 <head>
  <title>yaml page</title>
 </head>
 <body>
  <h1>yaml to XML を作る</h1>
  <p>ここに文章を書き下す。</p>
 </body>
</html>

XMLの書式に則るので、p タグや br タグの扱いが普段の HTML とは異なりますが、ある程度はこれでできるはずです。このあたりは、XAML の RichTextBlock に渡す糖化構文も合わせて考えていきたいところですね。

カテゴリー: 開発, C#, EXDoc パーマリンク