XML template with E4X

nnp_cooperation.js を HEAD の仕様に対応するために書き換えるついでに refactoring してたんだけど :nnpgetlist で table を構築する処理を E4X に切り替えた。

http://coderepos.org/share/changeset/25713

というのも http://d.hatena.ne.jp/teramako/20081113/p1 の影響で E4X の使い方をちょっとマジメに考えてたんだけど http://vimperator.org/trac/gitweb/?p=vimperator.git;a=blob;f=content/template.js;h=1a070f30f264c03bbb5aafbc4f93a6de6a2cb17b;hb=HEAD の後半で定義されてる method の例を見て template として使うと ( Perl でいう HTML::Template のノリで。ってまだ HTML::Template はメジャーなんかな ? ) かなりラクになるんじゃないかと思ってやってみたらビンゴだったので。まぁ XMLリテラルで書くのは慣れないと奇妙だし editor の syntax が対応してないと '/' に挟まれたところを正規表現として理解しちゃったりして書きにくいんだけど。

XML リテラルの中では {} に囲まれた式を評価してくれるので Perl の double quotation での変数指定ちっくに書けたり、関数の評価結果を埋め込んだりできてかなり楽。 HTML::Template に対応する TMPL_VAR だね。 TMPL_LOOP はそのままでは実現できないんだけど、 vimperator の提供している liberator.modules.template.map method を使うと似たことができる。そのまま持ってくるのはちょっと無理があったので適当に以下のように定義しておくと ( vimp のソースをおれ式に書き直したもの )

function tmpl_loop(data, action, separater) {
    let result = <></>;
    for (let i=0, l=data.length ; i<l ; ++i) {
        let v = action(data[i]);
        if (v === undefined) continue;
        if (separater && i) result += separater;
        result += v;
    }

    return result;
}

以下の感じで使うことができる。

let testdata = [
    [1, 'a', true],
    [2, 'b', false],
    [3, 'c', true],
];

/*
<tr>
    <td>2</td>
    <td>a</td>
    <td>ジュースをおごってやろう</td>
</tr><tr>
    <td>3</td>
    <td>b</td>
    <td>マジでかなぐり捨てンぞ?</td>
</tr><tr>
    <td>4</td>
    <td>c</td>
    <td>ジュースをおごってやろう</td>
</tr>
*/
let dom = tmpl_loop(testdata, function ([i, s, b]) {
    return <tr>
        <td>{i + 1}</td>
        <td>{s}</td>
        <td>{b ? 'ジュースをおごってやろう' : 'マジでかなぐり捨てンぞ?'}</td>
    </tr>
});

TMPL_IF や TMPL_UNLESS もやろうと思えばできると思う。まぁ TMPL_VAR と TMPL_LOOP があればたいていのことは足りるので上記だけでもあまり問題ないはず。