Eliom/Ocsigen の XHTML型

EliomではXHTMLを表現する型でページを構成する.たとえば、 というタグは型 [>`Html ] XHTML.M.elt の値として扱う. このおかげで、Eliomが出力するXHTMLは必ずwell-formedかつ(ほぼ?)validだ.
[>`Html ] XHTML.M.elt という型を見れば分かるように、 幽霊型として多相バリアントを使って XHTMLDTDを表現しているようだ。
たとえば、こんな風に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>"

&lt;strong&gt;hoge&lt;/strong&gt;

のように出力される.

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 が要らなくなる!!