読者です 読者をやめる 読者になる 読者になる

Arantium Maestum

プログラミング、囲碁、読書の話題

Clojure Web Development勉強 - Hiccup (その1)

Clojure Web Hiccup

今まで愚直にHTMLタグを文字列として書いてきたが、読むほうも辛かったと思うが書くほうはもっと辛かった。

まあ、ただこの時点では大して動的な機能もなく(唯一あったのはフォームから受け取った文字列を表示するくらい(ただしこれが「くらい」というには問題のありすぎることなのは後述する))、複雑なテンプレート機能を使う必要があったわけじゃないのも事実である。

ここから「すべてのページで共通の部分を表示させたい」「同じようなエレメントを複数回表示させたい」などといったニーズが生じていくにつれ、さらに「HTMLタグを文字列で」というアプローチは辛くなっていく。

ということで、より動的にHTMLを作成するテンプレートDSLを提供するライブラリHiccupを使ってみる。

HiccupはHTMLテンプレートとしてもかなり特殊で、Clojureの標準データ構造であるVectorとMapでタグとプロパティを表現する。

例えば

<div>
  <h1>Hello</h1>
  <p>My HTML document</p>
</div>

はHiccupだと

[:div
  [:h1 "Hello"]
  [:p "My HTML document"]]

となる。

いちいち</h1>と閉じなくて良くなった、というのはまあ小さなメリットである。より重要なメリットとして、Clojureデータ構造として表現されている以上、Clojureの豊富なデータ変換関数を使って非常に高い自由度で以って変換したり組み合わせたりすることが可能となっている。

Hiccupを使って今までのコードを書き直してみた。

gist.github.com

基本的に変更はview.cljの部分。hiccup.coreからhtmlマクロとh関数を使っている。

htmlはClojureデータ構造で定義されたhtml構造を正しいHTML文字列に変換するhiccupの根本となるマクロ。

REPLで試してみるとこんな感じ:

user=> (use 'hiccup.core)
nil
user=> (html [:div
  #_=>        [:h1 "Hello"]
  #_=>        [:p "My HTML document"]])
"<div><h1>Hello</h1><p>My HTML document</p></div>"

インデントは(当然といえば当然)再現されない。

なのでview.cljに定義されている関数は今までどおりHTMLタグ入りの文字列を返している。関数内部の表記がhiccupなだけである。

user=> (ns simple-hiccup.views)
nil
simple-hiccup.views=> (get-form {})
"<div><h1>Hello GET Form!</h1><p>Submit a message with GET</p><form action=\"get-submit\" method=\"get\"><input name=\"name\" type=\"text\" /><input type=\"submit\" value=\"submit\" /></form><p><a href=\"..\">Return to main page</a></p></div>"

個人的には、ここまで使った範疇だけでもHTMLの記法としてかなり良くできていて、HTMLタグを打つより断然Hiccupで書きたいと感じているのだが、これは個人の好みの問題かもしれない。近いうちにhiccupのより動的な機能や再利用性の向上を例を挙げて書きたい。

しかし、次の話題はhiccup.coreから呼び出しているもう一つの名称であるh関数とXSS攻撃についてである。