うならぼ

申し訳程度のアフィリエイトとか広告とか解析とかは/aboutを参照

C#でMustacheを使う

いや、RazorEngine使おうかと思ったんですけどね?

Install-Package : パッケージ 'RazorEngine 3.8.1' をインストールできませんでした。
このパッケージを '.NETFramework,Version=v3.5' を対象とするプロジェクトにインストールしようとしていますが、
そのフレームワークと互換性があるアセンブリ参照またはコンテンツ ファイルがパッケージに含まれていません。
詳細については、パッケージの作成者に問い合わせてください。

代わりにMustacheのC#実装であるNustacheを使ってみることにしました。

github.com

Mustache自体について説明しておくと、機能が少なくシンプルで、多数の言語で実装されているテンプレートエンジン、といったところでしょうか。

とりあえず.NETで利用可能なEncodingを列挙してみます。

var template = @"Available encodings:
{{#Encodings}}
- {{Name}} (cp{{CodePage}})
{{/Encodings}}";

var model = new
{
    Encodings = Encoding.GetEncodings()
};

var result = Nustache.Core.Render.StringToString(template, model);
Console.WriteLine(result);

本命は Render.Template(TextReader,TextWriter) ですが、入出力それぞれファイルや文字列に差し換えたものが Render.XXXToYYY() として用意されています。どれも RenderContextBehavior オブジェクトを渡すことで挙動を調整できますが、今のところモデル側が欠けてる時に例外投げるぐらいしかありません。

モデルはIList、IDictionary、フィールド・プロパティ・メソッドなどに対応しているようです。詳しくはソースコードValueGetterFactory.csあたりを参照。

テンプレートのコンパイル機能も Nustache.Compilation という別パッケージに用意されています。ただメンバの文字列変換にモデル型のToStringを使ってしまうようで、ToStringがオーバーライドされた型をモデルに使うとこけます。匿名型とか。そのうえ参照型のメンバに対して (value ?? "").ToString() みたいな式を生成するので、型が合わなくてやっぱりこけます。v1.16.0.1で修正されました。

さて、Mustacheも例によって記号類がHTMLエンティティに変換されます。それ以外の用途では邪魔なので無効化したいところですが、Nustacheの場合は Encoders.HtmlEncode に何もしないデリゲートを入れておけば回避できます。

// using Nustache.Core;

Console.WriteLine(Render.StringToString(@"{{str}}", new { str = "<&>" }));
// => &lt;&amp;&gt;

Encoders.HtmlEncode = x => x;

Console.WriteLine(Render.StringToString(@"{{str}}", new { str = "<&>" }));
// => <&>

// v1.16.0.1からは個別に設定することもできるようになりました
var behaviour = new RenderContextBehaviour { HtmlEncoder = x => x };
Console.WriteLine(Render.StringToString(@"{{str}}", new { str = "<&>" }, behaviour));

まあ、どうということもないですね。