如何在 Yesod 中呈现格式正确的字符串?

How can I render a string with proper formatting in Yesod?

我使用 tabular library 制作了一个 table。我使用这个库制作的 table 实际上只是一个带有很多换行符的奇特字符串。我想出如何使这个 table 正确格式化的唯一方法是在 repl.

中使用 putStr

如果我只显示字符串,我会返回一团乱麻,看起来像这样:

"+-----++-----------+-----------++-------------+-------------+\n|     || memtest 1 | memtest 2 || time test 1 | time test 2 |\n+=====++=

我希望做的是能够在 Yesod Handler Html 中以正确的格式呈现此 table。更具体地说,我想从 whamlet 模板中渲染这个 table。

我曾尝试使用 pShow 等函数合并 pretty-printing library,但未能成功。我浏览了各种 Yesod 库,但似乎无法确定任何有用的功能。

您的两个选择似乎是使用 HTML <pre> 元素按原样呈现 ASCII table 以获得“老式”外观,或重新呈现table 使用 tabular 对 HTML 的支持,以获得实际的 HTML <table> 元素。

最简单的方法是使用 <pre> 元素进行渲染。在 whamlet 模板中,只需将 ASCII table 插入模板:

import Yesod
import qualified Text.Tabular as T
import qualified Text.Tabular.AsciiArt as TA

example = T.Table
  (T.Group T.NoLine [T.Header "1", T.Header "2"])
  (T.Group T.SingleLine [T.Header "Table Type", T.Header "HTML Element"])
  [ ["ASCII art", "<pre>"], ["HTML", "<table>"] ]

asciiTable :: String
asciiTable = TA.render id id id example

getAsciiR :: Handler Html
getAsciiR = defaultLayout
  [whamlet|
    <p>My old-school table follows
    <pre>#{asciiTable}
    |]

使用 tabular 的 HTML 支持有点复杂,主要是因为它使用 Text.Html 和手工构建的 CSS,它们不直接与Yesod 的小部件和基于 blaze 的标记。但是,您可以像这样从头开始构建小部件:

import Yesod
import qualified Data.Text.Lazy.Builder as B
import qualified Text.Tabular as T
import qualified Text.Tabular.AsciiArt as TA
import qualified Text.Tabular.Html as TH
import qualified Text.Html as H

htmlTable :: Widget
htmlTable = do
  toWidget . preEscapedToMarkup . renderHtml $ tbl
  toWidget . CssBuilder . B.fromString $ TH.defaultCss
  where tbl = TH.render H.stringToHtml H.stringToHtml H.stringToHtml example
        renderHtml h = foldr ($) "" [H.renderHtml' 0 e | e <- H.getHtmlElements h]

然后使用小部件插值 (^{...}) 将其插值到 whamlet 模板中:

getHtmlR :: Handler Html
getHtmlR = defaultLayout
  [whamlet|
    <p>My fancy table follows:
    ^{htmlTable}
    |]

这将给出如下内容:

完整代码如下。您可以访问localhost:3000/asciilocalhost:3000/html查看结果:

{-# LANGUAGE OverloadedStrings     #-}
{-# LANGUAGE QuasiQuotes           #-}
{-# LANGUAGE TemplateHaskell       #-}
{-# LANGUAGE TypeFamilies          #-}

module TableServer where

import qualified Data.Text.Lazy.Builder as B
import qualified Text.Tabular as T
import qualified Text.Tabular.AsciiArt as TA
import qualified Text.Tabular.Html as TH
import qualified Text.Html as H

import Yesod

data Site = Site
mkYesod "Site" [parseRoutes|
  /ascii AsciiR GET
  /html  HtmlR  GET
  |]
instance Yesod Site

example = T.Table
  (T.Group T.NoLine [T.Header "1", T.Header "2"])
  (T.Group T.SingleLine [T.Header "Table Type", T.Header "HTML Element"])
  [ ["ASCII art", "<pre>"], ["HTML", "<table>"] ]

asciiTable :: String
asciiTable = TA.render id id id example

getAsciiR :: Handler Html
getAsciiR = defaultLayout
  [whamlet|
    <p>My old-school table follows
    <pre>#{asciiTable}
    |]

htmlTable :: Widget
htmlTable = do
  toWidget . preEscapedToMarkup . renderHtml $ tbl
  toWidget . CssBuilder . B.fromString $ TH.defaultCss
  where tbl = TH.render H.stringToHtml H.stringToHtml H.stringToHtml example
        renderHtml h = foldr ($) "" [H.renderHtml' 0 e | e <- H.getHtmlElements h]

getHtmlR :: Handler Html
getHtmlR = defaultLayout
  [whamlet|
    <p>My fancy table follows:
    ^{htmlTable}
    |]

main :: IO ()
main = warp 3000 Site