首页 > 解决方案 > 从 Hakyll 中的元数据创建列表字段

问题描述

我正在尝试为 Hakyll 中元数据中有versions条目的帖子生成 HTML。例如,一篇文章可能versions: Python 3.4, pytest 1.5.2会在文章底部很好地格式化。

为此,我想创建一个上下文来加载元数据并创建一个ListField. 类似于以下存根:

versionsCtx :: Context String
versionsCtx = listFieldWith "versions" ctx (\item -> do
    versions <- getMetadataField (itemIdentifier item) "versions"

    return $ case versions of
      Just lst -> map (mkVersinoItem . trim) $ splitAll "," lst
      Nothing  -> [])
          where ctx = field "version" (return . itemBody)
                mkVersionItem version = Item {
                    itemIdentifier = fromString ("version/" ++ version),
                    itemBody = version
                }

在我的post.html模板中,我有:

...
    <section>
        $body$

        $if(versions)$
        <hr />
        <ul>
            $for(versions)$
                <li>$version$</li>
            $endfor$
        </ul>
        $else$
            <p>Fail...</p>
        $endif$
    </section>
...

然而,我尝试了许多不同的定义,versionsCtx并在网上找到了类似的尝试。似乎没有任何工作,并且帖子总是以“失败......”呈现。我究竟做错了什么?

编辑:用建议和说明更新问题。

标签: metadatalistfieldhakyll

解决方案


您的代码存在多个问题:

  1. getMetadataField提供了一种Maybe类型,在 Haskell 中有数据构造函数Justand Nothing,而不是Someand None
  2. makeItem函数创建一个Item已经包装在 a 中的Compiler,导致以下错误:
• Couldn't match type ‘Compiler (Item String)’ with ‘Item String’
  Expected type: Compiler [Item String]
    Actual type: Compiler [Compiler (Item String)]

虽然您可以尝试从中提取项目,但使用以下内容从头开始创建项目可能更清洁:

mkVersionItem version = Item {
    itemIdentifier = fromString ("version/" ++ version),
    itemBody = version
}
  1. 我没有看到您将新创建的上下文添加到帖子上下文中。是你做的吗?
  2. 文档中所述,附加的 orderContext很重要。从您的问题中并不明显,但您可能正在使用defaultContext,其中包括metadataField. 您versions在帖子的元数据块中有字段,因此当defaultContext获胜时,它将versions作为模板中的字符串字段提供。$if(versions)$出于某种原因,当是一个字符串字段时跳转到else分支versions,这解释了为什么显示“失败”。当您将for循环移到条件块之外时,您可以在控制台中看到更多信息错误:
[ERROR] Hakyll.Web.Template.applyTemplateWith: expected ListField but got StringField for expr versions

完整的代码看起来像这样:

import           Data.String (fromString)

postCtx :: Context String
postCtx =
    versionsCtx `mappend`
    dateField "date" "%B %e, %Y" `mappend`
    defaultContext

versionsCtx :: Context String
versionsCtx = listFieldWith "versions" ctx (\item -> do
    versions <- getMetadataField (itemIdentifier item) "versions"

    return $ case versions of
      Just lst -> map (mkVersionItem . trim) $ splitAll "," lst
      Nothing     -> []
    )
  where
    ctx = field "version" (return . itemBody)
    mkVersionItem version = Item {
        itemIdentifier = fromString ("version/" ++ version),
        itemBody = version
    }

推荐阅读