Eliom/Ocsigen の XHTML型
EliomではXHTMLを表現する型でページを構成する.たとえば、 というタグは型 [>`Html ] XHTML.M.elt の値として扱う. このおかげで、Eliomが出力するXHTMLは必ずwell-formedかつ(ほぼ?)validだ.
[>`Html ] XHTML.M.elt という型を見れば分かるように、 幽霊型として多相バリアントを使って XHTMLのDTDを表現しているようだ。
たとえば、こんな風にXHTMLを書く:
html (head (title (pcdata "Hello")) []) (body [h1 [pcdata "Hello,World!"]]);;
headの引数が2つあるのは、 headの引数は1つ"以上"必要なので 1つめの子要素と 2つ目以降の子要素のリストを与えるようになっているため (だったと思う).徹底してます.
ここで たとえば bodyの直下に pcdata を置こうとすると
# body [pcdata "Hello, World!"];; Error: This expression has type ([> `PCDATA ] as 'a) XHTML.M.elt but an expression was expected of type ([< XHTML.M.block ] as 'b) XHTML.M.elt Type 'a is not compatible with type 'b = [< `Address | `Blockquote | `Del | `Div | `Dl | `Fieldset | `Form | `H1 | `H2 | `H3 | `H4 | `H5 | `H6 | `Hr | `Ins | `Noscript | `Ol | `P | `Pre | `Script | `Table | `Ul ] The second variant type does not allow tag(s) `PCDATA
のように怒ってくれる.DTDの違反が ほぼ 確実に型エラーとして検出されるわけだ.
他に、 OCamlDuce という より強力なXML型付けの処理系と連携させることもできる. 私は手元で ビルドできなかったので試していないけれど
no インジェクション
もちろん、HTMLやJavaScriptをインジェクションする余地はない. というと魔法のようだけれど、Eliomが提供するpcdata等のコンビネータは 特殊文字をエスケープしてくれる.
pcdata "<strong>hoge</strong>"
は
<strong>hoge</strong>
のように出力される.
XHTMLリテラル
camlp4 で xhtmlsyntax.cma を使えば、 XHTMLリテラルを使うこともできる. << ... >> で区切った部分に XHTMLを書く..
let h1 = << <h1>Hello!</h1> >>
<< .. >> の間に置ける要素は 1つだけのようだ (複数書いても無視される).
XHTMLリテラル中で,OCaml の式は $ .. $ の間に書く. この式は子要素になる部分に配置する.たとえば、上のコードは次と等価:
let h1 = << <h1>$ pcdata "Hello!" $</h1> >>
残念ながら $ はネストできない.
そのほか、 $str: (string型の値)$ とやれば、エスケープされない文字列を出力できるけれど、あまりやりたくないし、おすすめもできない.
コンパイル
とりあえず試したい場合は、
ocamlfind ocamlc -c -I . -thread -package extlib,ocsigen,pcre -pp "camlp4o /opt/local/lib/ocaml/site-lib/ocsigen/xhtmlsyntax.cma -loc loc" ファイル.ml
などとしてコンパイルすればいいだろうと思う. (追記)
ocamlfind ocamlc -c -I . -thread -package extlib,ocsigen,pcre,ocsigen.xhtml.syntax -syntax camlp4o ファイル.ml
ocamlfind のオプション -syntax を使えば -pp が要らなくなる!!