根据每个页面的元数据有条件地在上下文中包含一个字段
Conditionally including a field in the context based on each page’s metadata
我想在我的 Hakyll 站点的上下文中添加一个字段。如果某个键存在于元数据中,那么我想转换相应的值并将其包含在上下文中。如果密钥不存在于元数据中,则不应向上下文中添加任何内容。
我编写了这个函数,应该 执行我描述的操作:
-- | Creates a new field based on the item's metadata. If the metadata field is
-- not present then no field will actually be created. Otherwise, the value will
-- be passed to the given function and the result of that function will be used
-- as the field's value.
transformedMetadataField :: String -> String -> (String -> String) -> Context a
transformedMetadataField key itemName f = field key $ \item -> do
fieldValue <- getMetadataField (itemIdentifier item) itemName
return $ maybe (fail $ "Value of " ++ itemName ++ " is missing") f fieldValue
但是,如果元数据字段不存在,那么这仍会在上下文中插入一个字段,其值为空字符串。例如,我的上下文中有这一行:
transformedMetadataField "meta_description" "meta_description" escapeHtml
我有这个模板:
$if(meta_description)$
<meta name="description" content="$meta_description$"/>
$endif$
在其元数据中没有 meta_description
的页面上,会生成以下 HTML:
<meta name="description" content=""/>
而我想要的是根本不生成标签。
我的 transformedMetadataField
函数做错了什么?
您需要 return Control.Applicative 的 "empty" 才能让字段完全不存在。来自我自己的代码的示例:
-- What we're trying to do is produce a field that *doesn't* match
-- key in the case where the metadata "header" is not set to "no" or
-- "false"; matching it and returning false or whatever
-- (makeHeaderField above) isn't working, so any call to "field" is
-- guaranteed to not work
makeHeaderField :: String -> Context a
makeHeaderField key = Context $ \k _ i -> do
if key == k then do
value <- getMetadataField (itemIdentifier i) "header"
if isJust value then
if elem (fromJust value) [ "no", "No", "false", "False" ] then
-- Compiler is an instance of Alternative from
-- Control.Applicative ; see Hakyll/Core/Compiler/Internal.hs
CA.empty
else
return $ StringField $ fromJust value
else
return $ StringField "yes makeheader"
else
CA.empty
哦,我忘了:正如我上面的代码注释所指定的,在这种情况下你不能使用 hakyll "field" 函数,因为 "field" 在以下情况下始终将字段视为存在字段名称匹配。您必须从 "field" 复制代码才能在 CA.empty returns 上您想要的地方获得自己的代码,正如我在上面所做的那样(CA 是 Control.Applicative) .
为了后代,感谢@rlpowell 的回答,这是我最终得到的函数。
-- | Creates a new field based on the item's metadata. If the metadata
-- field is not present then no field will actually be created.
-- Otherwise, the value will be passed to the given function and the
-- result of that function will be used as the field's value.
transformedMetadataField :: String -> String -> (String -> String) -> Context a
transformedMetadataField newKey originalKey f = Context $ \k _ i -> do
if k == newKey
then do
value <- getMetadataField (itemIdentifier i) originalKey
maybe empty (return . StringField . f) value
else empty
我想在我的 Hakyll 站点的上下文中添加一个字段。如果某个键存在于元数据中,那么我想转换相应的值并将其包含在上下文中。如果密钥不存在于元数据中,则不应向上下文中添加任何内容。
我编写了这个函数,应该 执行我描述的操作:
-- | Creates a new field based on the item's metadata. If the metadata field is
-- not present then no field will actually be created. Otherwise, the value will
-- be passed to the given function and the result of that function will be used
-- as the field's value.
transformedMetadataField :: String -> String -> (String -> String) -> Context a
transformedMetadataField key itemName f = field key $ \item -> do
fieldValue <- getMetadataField (itemIdentifier item) itemName
return $ maybe (fail $ "Value of " ++ itemName ++ " is missing") f fieldValue
但是,如果元数据字段不存在,那么这仍会在上下文中插入一个字段,其值为空字符串。例如,我的上下文中有这一行:
transformedMetadataField "meta_description" "meta_description" escapeHtml
我有这个模板:
$if(meta_description)$
<meta name="description" content="$meta_description$"/>
$endif$
在其元数据中没有 meta_description
的页面上,会生成以下 HTML:
<meta name="description" content=""/>
而我想要的是根本不生成标签。
我的 transformedMetadataField
函数做错了什么?
您需要 return Control.Applicative 的 "empty" 才能让字段完全不存在。来自我自己的代码的示例:
-- What we're trying to do is produce a field that *doesn't* match
-- key in the case where the metadata "header" is not set to "no" or
-- "false"; matching it and returning false or whatever
-- (makeHeaderField above) isn't working, so any call to "field" is
-- guaranteed to not work
makeHeaderField :: String -> Context a
makeHeaderField key = Context $ \k _ i -> do
if key == k then do
value <- getMetadataField (itemIdentifier i) "header"
if isJust value then
if elem (fromJust value) [ "no", "No", "false", "False" ] then
-- Compiler is an instance of Alternative from
-- Control.Applicative ; see Hakyll/Core/Compiler/Internal.hs
CA.empty
else
return $ StringField $ fromJust value
else
return $ StringField "yes makeheader"
else
CA.empty
哦,我忘了:正如我上面的代码注释所指定的,在这种情况下你不能使用 hakyll "field" 函数,因为 "field" 在以下情况下始终将字段视为存在字段名称匹配。您必须从 "field" 复制代码才能在 CA.empty returns 上您想要的地方获得自己的代码,正如我在上面所做的那样(CA 是 Control.Applicative) .
为了后代,感谢@rlpowell 的回答,这是我最终得到的函数。
-- | Creates a new field based on the item's metadata. If the metadata
-- field is not present then no field will actually be created.
-- Otherwise, the value will be passed to the given function and the
-- result of that function will be used as the field's value.
transformedMetadataField :: String -> String -> (String -> String) -> Context a
transformedMetadataField newKey originalKey f = Context $ \k _ i -> do
if k == newKey
then do
value <- getMetadataField (itemIdentifier i) originalKey
maybe empty (return . StringField . f) value
else empty