Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the easiest way to generate an html table in haskell [closed]

Tags:

html

haskell

I would like to output a table in html format. Basically I would like something like :

[[a]] -> <table> 

What is the easiest way to do so ?

like image 221
mb14 Avatar asked Dec 09 '25 09:12

mb14


2 Answers

The easiest way to generate Html is probably blaze:

import Text.Blaze.Html5 (table, td, tr, toHtml, ToMarkup, Html)
import Control.Monad (forM_, mapM_)

myTable :: (ToMarkup a) => [[a]] -> Html
myTable xs = table $ forM_ xs (tr . mapM_ (td . toHtml))

Note that you need to use renderHtml from Text.Blaze.Renderer.* to get a ByteString, String or Text.

like image 160
Zeta Avatar answered Dec 11 '25 23:12

Zeta


Edit: During writing the answer @Zeta already posted a better solution using blaze-html. So I recommend using his solution (see section "Words of Warning" for the listening of this solutions disadvantages...) ;-)

Here is an implementation:

-- file test.hs:

insideTag :: String -> String -> String
insideTag tag content = "<" ++ tag ++ ">" ++ content ++ "</" ++ tag ++ ">"

toTable :: Show a => [[a]] -> String
toTable = insideTag "table" . concatMap (insideTag "tr") . map (concatMap (insideTag "td" . show))

main :: IO ()
main = do
    putStrLn $ toTable [[1,2,3],[4,5,6],[7,8,9]]
    return ()

The command runhaskell test.hs will now print

<table><tr><td>1</td><td>2</td><td>3</td></tr><tr><td>4</td><td>5</td><td>6</td></tr><tr><td>7</td><td>8</td><td>9</td></tr></table>

Explanation of the code

insideTag encapsulates content inside a html tag:

ghci> let insideTag tag content = "<" ++ tag ++ ">" ++ content ++ "</" ++ tag ++ ">"
ghci> insideTag "h1" "hello world"
"<h1>hello world</h1>"

map (concatMap (insideTag "td" . show)) list encapsulate the inner elements into <td> tags and concatenate them:

ghci> map (concatMap (insideTag "td" . show)) [[1,2], [3,4]]
["<td>1</td><td>2</td>","<td>3</td><td>4</td>"]

The same can be done for the outer list:

ghci> concatMap (insideTag "tr") ["<td>1</td><td>2</td>","<td>3</td><td>4</td>"]
"<tr><td>1</td><td>2</td></tr><tr><td>3</td><td>4</td></tr>"

The last string only has to be encapsulate into a <table> tag:

ghci> insideTag "table" "<tr><td>1</td><td>2</td></tr><tr><td>3</td><td>4</td></tr>"
"<table><tr><td>1</td><td>2</td></tr><tr><td>3</td><td>4</td></tr></table>"

Words of warning

The above code uses the normal [Char] type for strings which is not memory efficient. So I recommend that you use Data.Text if you deal with big tables (toTable remains the same, you just have to change show to pack . show; insideTag has to reimplemented for Data.Text).

There is also no HTML escaping for the table content!!! So the above code is vulnerable to XSS attacts. So do not use the above code, if the produced HTML shall be included in a website (especially if the website user has an influence on the table content)!

like image 44
Stephan Kulla Avatar answered Dec 12 '25 00:12

Stephan Kulla



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!