• 作成:

HakyllサイトのHTML特殊文字が二重エスケープされてしまうのを正規表現によって解決

このサイトのdescriptionやteaserといったものは

teaserFieldByResource :: Int -> String -> Snapshot -> Context String
teaserFieldByResource l key snapshot = field key $ \item ->
    escapeHtml . take l . stripTags . itemBody <$> loadSnapshot (itemIdentifier item) snapshot

によって作られているのですが, snapshotが既に特殊文字エスケープされているにもかかわらず, escapeHtmlを実行してしまっているため, &が二重にエスケープされていました. その結果, <&amp;gt;になってしまったり問題が生じていました.

かと言ってescapeHtmlを外せば良いというわけではなく, takeによってHTMLがぶつ切りに切断されているため, 外すと&lt;が途中の;が無く切られてしまい, tidy HTMLに怒られることになります.

この問題を解決するために, dropWarningHtmlEntityという関数を書くことにしました. この関数は文字列の最期の&を検索し, それに;が続いていなければ最期の&以下を消去してしまう関数です. これでフィルタリングすればtidy HTMLには怒られなくなるはずです.

正規表現で実装できそうですね.

実装できました.

teaserFieldByResource :: Int -> String -> Snapshot -> Context String
teaserFieldByResource l key snapshot = field key $ \item ->
    dropWarningHtmlEntity . take l . stripTags . itemBody <$>
    loadSnapshot (itemIdentifier item) snapshot

dropWarningHtmlEntity :: String -> String
dropWarningHtmlEntity entity = R.subRegex (R.mkRegex "&[^&;]*$") entity ""