2007-10-30

[]55行で作るC#テンプレートエンジン

http://anond.hatelabo.jp/20071030034313二番煎じ

あまりのアホさに、作ってて気が狂いかけた

方針


using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using Microsoft.CSharp;

delegate void ConvertTemplateDelegate(TextWriter tw, Dictionary<object, object> args);
static class TemplateGenerator {
    public static ConvertTemplateDelegate Generate(string code) {
        CompilerParameters param = new CompilerParameters();
        param.GenerateInMemory = true;
        param.ReferencedAssemblies.Add("System.Web.dll");
        CompilerResults rs = new CSharpCodeProvider().CompileAssemblyFromSource(param, ParseTemplate(code));
        if (0 < rs.Errors.Count) {
            StringWriter sw = new StringWriter();
            sw.WriteLine("Compile Error...");
            foreach (CompilerError err in rs.Errors)
                sw.WriteLine(err.ToString());
            throw new Exception(sw.ToString());
        }
        return (ConvertTemplateDelegate) Delegate.CreateDelegate(typeof(ConvertTemplateDelegate), rs.CompiledAssembly.GetType("Template", true).GetMethod("Convert"));
    }
    private static string ParseTemplate(string code) {
        using (StringWriter sw = new StringWriter()) {
            sw.WriteLine("using System; using System.Collections.Generic; using System.IO; using System.Web;");
            sw.WriteLine("public static class Template {");
            sw.WriteLine("public static void Convert(TextWriter tw, Dictionary<object, object> args) {");
            int index = 0;
            while (0 <= index &amp;&amp; index < code.Length) {
                int i = code.IndexOf("<%", index);
                sw.WriteLine("tw.Write(\"{0}\");", EscapeString(i < 0 ? code.Substring(index) : code.Substring(index, i - index)));
                if (0 <= i) {
                    i += 2;
                    int i2 = code.IndexOf("%>", i);
                    if (0 <= i2) {
                        string cc = code.Substring(i, i2 - i);
                        if (cc.StartsWith("="))
                            sw.WriteLine("tw.Write(HttpUtility.HtmlEncode(\"\"+({0})));", cc.Substring(1));
                        else
                            sw.WriteLine(cc);
                        i = i2 + 2;
                    }
                }
                index = i;
            }
            sw.WriteLine("}}");
            return sw.ToString();
        }
    }
    private static string EscapeString(string code) {
        return code.Replace("\\", "\\e").Replace("\"", "\\\"").Replace("\t", "\\t").Replace("\n", "\\n").Replace("\r", "\\r").Replace("\\e", "\\\\");
    }
}

サンプル C# コード。ためしにテンプレートから Xml 生成して、標準出力してみる。

class Program {
    static void Main(string[] args) {
        ConvertTemplateDelegate func = TemplateGenerator.Generate(TemplateEngine.Resource1.template);
        using (StringWriter sw = new StringWriter()) {
            Dictionary<object, object> arg = new Dictionary<object, object>();
            arg["title"] = "template sample";
            arg["data"] = new string[] { "foo", "fooo", "<strong>foooooooooo!</strong>" };
            func(sw, arg);
            Console.WriteLine(sw);
        }
    }
}

サンプルテンプレート

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <title><%= args["title"] %></title>
  </head>
  <body>
    <h1><%= args["title"] %></h1>
    <table>
<% string[] data = (string[]) args["data"]; %>
<% for(int i = 0; i < data.Length; i++) { %>
      <tr bgcolor="<%= i % 2 == 0 ? "#FFCCCC" : "#CCCCFF" %>">
        <td><%= i %></td>
        <td><%= data[i] %></td>
      </tr>
<% } %>
    </table>
  </body>
</html>

出力例

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <title>template sample</title>
  </head>
  <body>
    <h1>template sample</h1>
    <table>


      <tr bgcolor="#FFCCCC">
        <td>0</td>
        <td>foo</td>
      </tr>

      <tr bgcolor="#CCCCFF">
        <td>1</td>
        <td>fooo</td>
      </tr>

      <tr bgcolor="#FFCCCC">
        <td>2</td>
        <td>&lt;strong&gt;foooooooooo!&lt;/strong&gt;</td>
      </tr>

    </table>
  </body>
</html>

CodeDom 使って動的コンパイル……って、このコードのままだとセキュリティ的に大問題な気がするな。

素直に ASP.NET 使ったほうが楽だと直感した。

あと EscapeString すっごく自信ない。たぶん修正が必要だと思うw

記事への反応 -
  • 前の60行テンプレートエンジンを改良して、レイアウトテンプレート機能を追加してみた(それでも全部で90行)。 レイアウトテンプレート機能とは、例えば個別のテンプレートが&lt;tabl...

    • 唐突に、PHP用のテンプレートエンジンを作ってみる。 方針: ふつうのPHPファイルをテンプレートとして使う。 &lt;?php echo $var; ?&gt; は面倒なので #{$var} と書けるようにする。 &lt;?php e...

      • http://anond.hatelabo.jp/20071030034313 の二番煎じ あまりのアホさに、作ってて気が狂いかけた 方針 &lt;%= expr %&gt; で C# の式を echo(Htmlエスケープ付き) &lt;% code %&gt; で C# のコードを埋め込み eva...

      • つかわさせてもらってええのん?

      • 60行で作るPHP用テンプレートエンジン やってしまった・・・。 方針: PHPのように<?php・・・?>が無いのでそのまま表示と(foreach|if|unless)に対応。 [% $c{title} %]で普通に表示(TTっぽい?...

        • 40行で作るPerl用テンプレートエンジン PerlのClass::Data::Inheritableの解析 [perl]「,」と「=&gt;」の違いについて [perl]内部的に数値か文字かを判別する Shift_JISにおける危険な文字まとめ [perl...

          • 結論→一緒。 すまん嘘。 ほぼ同じ意味だって言いたかったの。カンマもイコールダイナリもほとんど同じ感覚で使用できる。 唯一つ違うのはイコールダイナリの左辺に置いた文字列は...

          • どうーでもいいーですよー。 どうでもいい話ー、聞いてください。 Perlというやつは一応内部的には数値か文字列かをちゃんと分けて変数の管理をしているのです。 でわ、現在ある変...

          • 今時Shift_JISでプログラミングするバカな奴はいないだろうけど折角まとめたので公開 2バイト目がアスキーコードど丸被りしているものを列挙する @ [ \ ] ^ _ ` { &#124; }...

            • 私は単なる一増田でしかないのだが、なんとなく今日を増田的情報セキュリティの日とすることに決めた。 なぜって、今日は、年末年始という忙しく、そして狙われやすい時期をはさみ...

            • Shift_JISにおける危険な文字まとめ 携帯サイトをUTF-8で出力するかShift_JISで出力するか - F.Ko-Jiの「一秒後は未来」

          • autoboxが流行ってるのになんで誰もコレを作らないのか不思議遊戯 package autobox::Unix;sub SCALAR::rm { my $dir = shift; my $option = shift; `rm $option $dir`;}# etc・・・use autobox;use autobox::Core;use autobox...

          • function qw ($str) { return preg_split(&#39;/&#92;s+/&#39;,$str,-1,PREG_SPLIT_NO_EMPTY);}$data = qw(&#39; hoge muge dae&#39;);print_r($data); にゃろめ。 プログラ増田のあなぐら

          • そろそろ FizzBuzz に飽きた - にぽたん研究所 NabeAtzzが空前のブームということで俺もRubyで書いてみた。 list = %W/さん ろく きゅう じゅうに じゅうさん じゅうご じゅうはち にじゅういち ...

          • フレームワークとか使ってるともはや隠蔽されすぎて自分で実装しようなんて思わないのが普通である。 ましてや車輪の再開発などもってのほか、バグを生み出す温床にしかならない。 ...

            • ブコメの。 さそりアーマーに殺される夢を見た増田 俺はさそりアーマーに殺される夢を見たな 80年代女性アイドル論の増田 マスダ80年代女性アイドル論~総論 おまえは今まで食っ...

          • 唐突にClass::Data::Inheritableのソースコードについて説明してやんよ。 使い方とかの説明はこの辺でも読んでから出直して来い、ごるぁ! まぁとりあえずソース見てみろ、下記にはっつけ...

          • 4Uって知ってるかい? http://4u.straightline.jp/ ”世界中の美女画像を皆でシェアするソーシャルイメージブックマークサービス” とのことさ。それはほんともう美しい画像が満載で毎日見...

          • 最近Perl界隈ではMoose、MooseってなんかMooseってのが流行ってるらしい。 もう完全に出遅れてしまったので増田で書き殴ってみる。 自分自身のブログでは、さもずっと前からMoose知ってた...

          • おれはもうMooseしかつかわねぇ。後にも先にもMooseMooseMooseMooseMoose!!!!!!!!!!!1111111 ってな人の為にいつでもどこでもMooseする。automooseを実装しますた。 package automoose;use stric...

          • 例えば下記の擬似コード i = 1; while( i &#38; 7 ) { i++; } 勘弁して。いや、わかるよ。言いたいことはさ。でも俺こういう書き方慣れてないから脳内で素早く2進数変換できないの。 いや単...

          • つまり下記のような書き方をした場合の話 [http://anond.hatelabo.jp/0000000:title=あああテスト] キーワードがリンクされてしまってうまくリンク名として認識されない。 詳しくはこの記事を読...

          • if ("0x0A" == "10") { print '(´ε` )チュッ';} チュッ。されちゃいます。 文字列であっても整数と解釈できる文字列の場合は勝手に型変換しやがる今世紀最大の愚行を犯してしまうっての...

            • 興味深い。できたらblogでやってほしいところ。 増田だと流れちまうからなあ。

            • プログラミングのこういう細かいところが死ぬほど嫌い。発狂するほど嫌い。 文字コードとかマジクソが死ねよって感じ。 こういうののせいでいつまでたってもプログラミングが好きに...

              • PHPみたいな糞とまともなプログラミング言語を一緒にするなよw 文字コードについては言語レベルではどうにもならんことはあるが、他の言語での扱いは少なくともPHPよりは楽。 バッド...

                • PHPに限らず、CとかC++もめんどくせーこと多くて嫌いなんだよ…。 あ、C/C++もまともな言語じゃないっすか。そうっすか…。

                  • C/C++はあくまでもCPU依存性を減らしたアセンブラであって、面倒くささを耐える代わりに速度を稼ぐという特殊用途言語なんだから、「プログラミングは面倒だ」というには局所的すぎる...

                    • バッドノウハウ…! これですよ。こういうのがマジウザい。 何がバッドノウハウだよただ仕様が終わってるだけじゃねーかカスが!って思う。 ああいうクソ仕様素晴らしい仕様をいか...

                      • バッドノウハウってのはかっこつけた単語じゃなくて、奥が深い症候群を戒めた語だよ。 自分が知ってる「業界の雰囲気」ってのが偏ったものだと知覚した方がいい。 それが相応しい...

                  • C・C++の面倒くさいことって具体的に何? 自分は仕VB・C・C++しか使ったことないが、面倒くさいと思ったことない。 他の言語ってそんなに楽なんだろうか?

                    • その経歴なら是非スクリプト言語を使ってみることを勧める。 Ruby, Perl, Pythonのうち1つは覚えた方がいい。絶対役に立つよ。 一昔前ならPerlを進めてたところだけど、今ならRubyかな。 ht...

                    • 型。状況や文脈を判断してよきに計らってほしい。 ポインタ。と言うよりメモリ管理か。必要に応じて増やすなり減らすなりよきに計らってほしい。

                    • めんどくせーめんどくせー言ってる増田だけど。 C/C++はまずガベージコレクタが無いのがめんどくさすぎる。いちいちライブラリ導入したりboostのスマートポインタ使ったりしなきゃいけ...

                      • 適材適所 sed ちょっとした正規表現抜き出しに perl そこそこの文書処理に Java わりと何でもいけるが、わりと平均的にめんどくさい JSP メモリ64K制限さえなければすばらしかったが、Ja...

            • PHPで一番困るのは、この手の変換が直感的でも統一的でもなことだな。 「自分が何をしようとしているのか」が素直に書けないんだよね。 言語として元になっているPerlにも文字と数値...

            • PHPの「==」は「数値として比較する」ためのものであって、そもそも文字列として比較するときに使うためのものではないという説。 文字列比較を意図するのであれば、 if (strcmp(&quot;0x0A...

              • 文字列比較を意図するのであれば、 if (strcmp("0x0A", "10")) { print '(´ε` )チュッ';} とすべき。当然チュッされない。 strcmp()は文字列が等しいときに0になるから、これだとチュッされ...

              • そこの増田よ。 strcmpの使い方を間違っておられる。 さっと手元で書いたから間違えたのならまだいいが、いつもその書き方をしてるのなら君書いたプログラムには重大なバグが潜んで...

            • ===演算子を使えよ if ("0x0A" === "10") { print '(´ε` )チュッ';}else{ print '\(^o^)/';} \(^o^)/ ==演算子は方をキャストしながら、ほぼ同じなら同じと見なせという意味。 HTMLとかで曖昧に...

              • 自己レス 012とかは、よく桁のパディングで 000001 と 1が同じであることを見つけるとかって処理をするから、8進数と見なしてくれるより、10進数で0詰めって見なしてくれた方が、テキ...

              • もちつけ。 ===演算子を使うなとは書いてないし、8進数使いたいとも書いてない。 元記事はただ事実をありのまま書いているだけだ。 そして誰も「つのだ★ひろ」には突っ込まないw

            • PHPコーディング規約  http://www.sksk.info/php.html 404 Blog Not Found:そろそろPHPに関して一言いっとくか  http://blog.livedoor.jp/dankogai/archives/50835571.html 404 Blog Not Found:「PHPなめんな」と「(Perl|Pytho...

              • こうやって並べてみると PHP(C/Java/Ruby/Python好きな物に置換可能)は、良い・悪いの議論って、 本当に、隣の葡萄はすっぱい。俺のレモンは甘い 議論なんだなぁと。

            • プログラミング言語ヒエラルキーにおける罵倒 http://anond.hatelabo.jp/20070502200124 phpのいやなところ / perlのいやなところ http://anond.hatelabo.jp/20070522174725 LL編プログラミング言語ヒエラルキーに...

          • 元ネタ http://phpspot.org/blog/archives/2009/12/phpjavascriptph_1.html 面白そうだと思ったので僕もやってみた。モジュールはPerl5.8系の標準モジュールのみ利用可という制限。 全部はキツイので関数...

          • ひーほー。いやぁさてさて一体このコード中に何度create_functionで匿名関数が生成されたのかふと気になったあなたのためにこんな関数を作ってみたよ! function get_lambda_functions () { $i ...

          • を作ってみた。 うたまっぷ javascript:(function(){%20var%20t;%20var%20d=document;%20var%20h=new%20XMLHttpRequest();%20var%20r=d.location.href.match(/surl=([A-Za-z0-9]+)/);%20h.open('GET','phpflash/flashfalsephp.php?unum=?'+r[1],true);%2...

          • &#82;&#117;&#98;&#121;&#12391;&#12358;&#12393;&#12435;&#12370;&#81;&#117;&#105;&#110;&#101;&#40;&#12392;&#65;&#65;&#22411;&#81;&#117;&#105;&#110;&#101;&#12398;&#20316;&#12426;&#26041;&#35611;&#24231;&#41; &#112;&#101;&#114;&#108;&#32;&#45;&#32;&#81;&#...

          • 以下の記事を読んだ私は違和感を覚えた。 &#31169;&#12364;&#12477;&#12501;&#12488;&#12454;&#12455;&#12450;&#25216;&#34899;&#32773;&#12434;&#12420;&#12417;&#12383;&#29702;&#30001; 今時のソフトウェア技術者というものは...

            • sqlとかでisdateしてやれば済むお話しさー。 最初の要件定義にうるう年について書かれていなければ、うるうどしが来たらうるう年対応でお金をもらえばいいじゃない。 というより、綺麗...

              • 超人が500行で1時間で書いたスマートなプログラムよりも、凡人が10000行、1カ月かけてつくったプログラムのほうがお金にはなるんだ。 マジレスすると、上記の条件であれば、案件...

          • http://1-byte.jp/2011/03/20/20_tips_you_need_to_learn_to_become_a_better_php_programmer/ 良いPHPerだって?そんなものは丸めてゴミ箱にでも捨ててしまった方が資源の再利用になる分いくらかマシだ。 つまり...

            • ペロペロ 1. htmlのはき出しがあるやつは?&gt;を書いたほうがいいよ。それ以外は最近はかないのがはやりだねさらに昔はevalとかで書いてた 2. configこれはwwwやpublic_html以下にしかconfigを配...

            • 21. 分散SCMを使え なにはともあれまずはコミットだ 粒度だクソだはpushするときにかんがえろ 1コミットで合わせて全然関係ない別の場所を変更したおまえは死刑だ

          • http://anond.hatelabo.jp/20130322031333 プログラミング出来る方法教えるだって?そんなものは丸めてゴミ箱にでも捨ててしまった方が資源の再利用になる分いくらかマシだ。 こんなタイトルに...

            • http://anond.hatelabo.jp/20130322202542 コレ見て書いてみたくなっただけ。 英語が話せるようになる方法教えるだって?そんなものは丸めてゴミ箱にでも捨ててしまった方が資源の再利用になる...

            • http://anond.hatelabo.jp/20130322202542 コレ見て書いてみたくなっただけ。 英語が話せるようになる方法教えるだって?そんなものは丸めてゴミ箱にでも捨ててしまった方が資源の再利用になる...

            • http://anond.hatelabo.jp/20130322202542 コレ見て書いてみたくなっただけ。 英語が話せるようになる方法教えるだって?そんなものは丸めてゴミ箱にでも捨ててしまった方が資源の再利用になる...

            • http://anond.hatelabo.jp/20130322202542 コレ見て書いてみたくなっただけ。 英語が話せるようになる方法教えるだって?そんなものは丸めてゴミ箱にでも捨ててしまった方が資源の再利用になる...

            • http://anond.hatelabo.jp/20130322202542 コレ見て書いてみたくなっただけ。 英語が話せるようになる方法教えるだって?そんなものは丸めてゴミ箱にでも捨ててしまった方が資源の再利用になる...

            • http://anond.hatelabo.jp/20130322202542 コレ見て書いてみたくなっただけ。 英語が話せるようになる方法教えるだって?そんなものは丸めてゴミ箱にでも捨ててしまった方が資源の再利用になる...

            • http://anond.hatelabo.jp/20130322202542 コレ見て書いてみたくなっただけ。 英語が話せるようになる方法教えるだって?そんなものは丸めてゴミ箱にでも捨ててしまった方が資源の再利用になる...

            • http://anond.hatelabo.jp/20130322202542 コレ見て書いてみたくなっただけ。 英語が話せるようになる方法教えるだって?そんなものは丸めてゴミ箱にでも捨ててしまった方が資源の再利用になる...

      • キャッシュ無しかよ。 中卒の俺でもこの程度のもの自作で持ってるぞ。

      • PHP自体がもともとPerlで作られたHTML用のテンプレートエンジンのようなもんなんだから 独自タグだけじゃなくてそれ以外の機能がないとPHPでテンプレートエンジンを使う意味があまりない...

        • smatyもそうだけどphpでテンプレート機能があると、 rubyのrhtmlファイルみたいにできていいじゃない? PHP自体がもともとPerlで作られたHTML用のテンプレートエンジンのようなもんなんだか...

      • Smartyあるからいらない

      • 今更だけど60行で作るPHP用テンプレートエンジンをクラス化した。 PHP5で動かしてね 細かい使い方はコード見て適当に判断してね もちろん改変、商用利用自由にね サンプルテンプレー...

    • レイアウト機能ってあれか、PerlのTemplate-ToolkitのWRAPPERみたいなもんか。 Smarty版もここにあるね→やたーーSmartyでTTのWRAPPERエミュレーションができたよーー - サタケ家

記事への反応(ブックマークコメント)

ログイン ユーザー登録
ようこそ ゲスト さん