Text.Htmlを使ってHTMLを出力

HaskellCGIを作る、続きです。

やはりCGIはHTMLを出力してこそ。でも文字列連結でHTMLを作るのはちょっとかんべん。
テンプレートエンジンをインストールしてもいいのだけど、GHCに付属しているText.Htmlというライブラリがあったので使ってみました。

Text.Htmlパッケージを触る

押さえておくべき演算子はこれ。

+++

あるノードの後ろに兄弟ノードを追加します。

タグに属性を付与する演算子も大事そう。

!

例えば2つのliタグを入れ子に持つulタグは以下のように表現出来ます。

q = (ulist ! [identifier "a"]) (
    li ( primHtml "list1" )
    +++ li ( primHtml "list2" )
  )

上記コードは以下のHTMLになります。

<UL ID = "a">
   <LI>
      list1
   </LI>
   <LI>
      list2
   </LI>
</UL>

使ってみた感想

各タグに相当する便利関数が提供されているものの、タグが大文字で出力されてしまうのがちょっと気持ち悪い。属性名も大文字です。

あと「関数の組み合わせで文書構造を表現する」というアプローチは面白いのですが、HTMLを直接書くのに比べたら、やはり表記が複雑になります。Haskellは表記が簡潔だからそこそこ書けるレベルではありますが、素でHTMLを書くのとは比べるべくもないです。当然ですけど。

CGIに組込む

組み込んでみました。一応、クエリストリングから文字列を得て動的に編集するロジックを入れています。

#! /usr/local/bin/runghc
module Main where

import Text.Html
import Network.CGI
import Data.Maybe

main = runCGI $ handleErrors $ cgiMain

cgiMain :: CGIT IO CGIResult
cgiMain = setHeader "Content-Type" "text/html; charset=UTF-8"
  >>  html
  >>= \html -> output ("<!doctype html>\n" ++ prettyHtml html)

html :: MonadCGI m => m Html
html = findVar "test"
  >>= \test -> findVar "var"
  >>= \var  -> return $
  header (
    meta ! [strAttr "charset" "UTF-8"]
    +++ thetitle ( primHtml "Welcome, Haskell's CGI world!!" )
  )
  +++ body (
    h1 ( primHtml "aaaaaaaaaaa" )
    +++ paragraph ( primHtml "bbbbbbbbbbb" )
    +++ h2 ( primHtml var )
    +++ paragraph (
      primHtml "cccccccccc"
       +++ ulist (
        li ( primHtml "ddddddd" )
        +++ li ( primHtml test )
      )
    )
  )

findVar :: MonadCGI m => String -> m String
findVar name = getInput name
  >>= \v -> case v of
              Just v  -> return v
              Nothing -> return ("**"++name++"**")

ベタだけど、できた!
ただ、モナド地獄に陥ってる感がありますね。全ての関数がモナド
絡んでて、このままではテストしにくいんじやないかなーと思います。