C#、言語内DSLでHTML構築、の試案

生成ターゲット:

<html>
    <head><title>hoge</title></head>
    <body>
        <h1>hoge</h1>
        <p><strong>hoge</strong></p>
        <p class="hoge" id="the_text">this is the text</p>
        <ul>
            <li>item1</li>
            <li>item2</li>
            <li>item3</li>
        </ul>
    </body>
</html>
var list=new[]{"item1","item2","item3"};

//plan a
HtmlBuilder.Begin(s=>{
    s.html(()=>{
        s.head(()=>{ s.title("hoge") });
        s.body(()=>{
            s.h1(()=>s.text("hoge"));
            s.p(()=>s.htmlfragment("<strong>hoge</strong>"));
            s.p(HtmlAttribute.class("hoge","hage"),HtmlAttribute.id("the_text"),()=>s.text("this is the text"));
            s.ul(()=>{
                foreach(var item in list)
                    s.li(()=>s.text(item));
            });
        })
    })
})
//plan b
HtmlBuilder b;
b.html()
    .head().title().text("hoge").end().end()
    .body()
        .h1().text("hoge").end()
        .p().htmlfragment("<strong>hoge</strong>").end()
        .p(HtmlAttribute.class("hoge","hage"),HtmlAttribute.id("the_text")).text("this is the text").end()
        .ul()
            .code(()=>{
                foreach(var item in list)
                    b.li().text(item).end();
            })
        .end();
    .end()
.end()
//plan c
HtmlBuilder.Begin(t=>{
    t.html & (
        (t.head & t.title & t.text("title"))
        +t.body & (
            (t.h1&t.text("hoge"))
            +(t.p&t.htmlfragment("<strong>hoge</strong>"))
            +(t.p.attr_class("hoge","hage").attr_id("the_text")&t.text("this is the text."))
            +t.ul&(t.code(()=>{
                foreach(var item in list)
                    t.li&t.text(item);
            }))
        )
    )
})
  • plan a
    • ラムダ式かわいい
    • 閉じタグの整合がコンパイル時に保障される
    • インデントをエディタに任せられる
  • plan b
    • end()がいっぱいあるよー(でも記述量はそう変わらないな)
    • こっちのほうがちょっと速そう(デリゲート呼び出しのぶん。誤差の範囲か)
    • 自動インデント禁止
    • 流れるようなインタフェース
  • plan c
    • これが本当に実装できるのかどうかわからない
    • 演算子オーバロードかっこいい!
    • みためシンプル