HTMLクラスの中身
私は、PerlのCGIモジュールにならったHTMLを取り扱うクラスを作り、それを使ってCGIを書いています。例えば次のように書くと、
import html sitetitle = u'サイト名' ht = html.HTML(encode=u'utf-8', lang=u'ja', sitetitle=sitetitle) ht.printe(ht.p(ht.a(attrs={u'href': u'./example.html'}, content=u'例えばのリンク')))
こんな風に出力してくれます。
<p><a href="./example.html">例えばのリンク</a></p>
これが本当に便利なのかはわからないけれど、私にとっては慣れたやりかたなので、当座、これでいこうと思っています。
このp()メソッドやa()メソッドは、内部で_create_element()メソッドを呼び出しているだけです。
def p(self, content, attrs=None): return self._create_element(u'p', content, attrs) def a(self, content, attrs=None): return self._create_element(u'a', content, attrs)
で、この_create_element()メソッドは、内部で_create_start_tag()メソッドと_create_end_tag()メソッドを使っています。この_create_start_tag()が生成するHTMLの開始タグ内の属性値を、cgi.escape()を使ってエスケープするようにしました。というか、当然最初からやっとくべきことなんだけど、わかっていながら放ってました。
タグの生成を、こうしてメソッド(関数)を使うようにしておくと、修正箇所が少なくて便利ですね。というか、ここだけ修正すればいいってわかってたから、ずっと放っておいたともいえます。
エレメントやタグを作るメソッドには、_create_empty_element()メソッドというのもあって、これは空要素を作ります。これの属性値もエスケープするようにしたので、いちいちエスケープしてから投げる必要がなくなりました。
エレメントの中身については、HTMLが入れ子になることもあるので、ユーザーが入力した値など、エスケープしておきたい、あるいはしなければならない文字列は、自分でやっておかないといけません。このへんは使う際に意識しておかないと、ごっちゃになりそうなので、一応メモとして残しておきます。
以下に_createなんたらのメソッドの中身を書いておきます。しかし、私の書くのはいちいちまどろっこしい、スマートさに欠けるものです。うまい人が書いたら、もっとコンパクトになるんでしょうね。
def _create_start_tag(self, elemname, attrs=None): starttag = u'<' + elemname if isinstance(attrs, dict): for attrname in (attrs.keys()): if attrs[attrname] is not None: attrvalue = attrs[attrname] if isinstance(attrvalue, int): attrvalue = str(attrvalue) starttag = starttag + u' ' + cgi.escape(attrname, True) + \ u'="' + cgi.escape(attrvalue, True) + u'"' starttag = starttag + u'>' return starttag def _create_end_tag(self, elemname): endtag = u'</' + elemname + u'>' return endtag def _create_element(self, elemname, content, attrs=None): starttag = self._create_start_tag(elemname, attrs) endtag = self._create_end_tag(elemname) if isinstance(content, int): content = str(content) if isinstance(content, basestring): return starttag + content + endtag else: raise TypeError(u'need string or int, got %r' % \ type(content)) def _create_empty_element(self, elemname, attrs=None): tag = u'<' + elemname if isinstance(attrs, dict): for attrname in (attrs.keys()): if attrs[attrname] is not None: attrvalue = attrs[attrname] if isinstance(attrvalue, int): attrvalue = str(attrvalue) tag = tag + u' ' + cgi.escape(attrname, True) + u'="' + \ cgi.escape(attrvalue, True) + u'"' tag = tag + u' />' return tag