json - Haskell::Aeson::根据字段值解析ADT

标签 json parsing haskell aeson

我正在使用一个返回 JSON 响应的外部 API。其中一个响应是对象数组,这些对象由其中的字段值标识。我在理解如何使用 Aeson 解析这种 JSON 响应时遇到了一些麻烦。

这是我的问题的简化版本:

newtype Content = Content { content :: [Media] } deriving (Generic)

instance FromJSON Content

data Media =
  Video { objectClass :: Text
        , title :: Text } |
  AudioBook { objectClass :: Text
            , title :: Text }

在 API 文档中,据说可以通过字段 objectClass 来识别对象,该字段对于我们的 Video 对象具有值“video”,对于我们的 AudioBook 等具有值“audiobook”。示例 JSON:
[{objectClass: "video", title: "Some title"}
,{objectClass: "audiobook", title: "Other title"}]

问题是如何使用 Aeson 处理这种类型的 JSON?
instance FromJSON Media where
  parseJSON (Object x) = ???

最佳答案

你基本上需要一个函数Text -> Text -> Media :

toMedia :: Text -> Text -> Media
toMedia "video"     = Video "video"
toMedia "audiobook" = AudioBook "audiobook"
FromJSON实例现在非常简单(使用 <$><*> 中的 Control.Applicative ):
instance FromJSON Media where
    parseJSON (Object x) = toMedia <$> x .: "objectClass" <*> x .: "title"

但是,此时您是多余的:objectClass Video 中的字段或 Audio不会为您提供比实际类型更多的信息,因此您可以将其删除:
data Media = Video     { title :: Text }
           | AudioBook { title :: Text }

toMedia :: Text -> Text -> Media
toMedia "video"     = Video
toMedia "audiobook" = AudioBook

另请注意 toMedia是局部的。您可能想捕获无效的 "objectClass"值(value)观:
instance FromJSON Media where
    parseJSON (Object x) = 
        do oc <- x .: "objectClass"
           case oc of
               String "video"     -> Video     <$> x .: "title"
               String "audiobook" -> AudioBook <$> x .: "title"
               _                  -> empty

{- an alternative using a proper toMedia
toMedia :: Alternative f => Text -> f (Text -> Media)
toMedia "video"     = pure Video
toMedia "audiobook" = pure AudioBook
toMedia _           = empty

instance FromJSON Media where
    parseJSON (Object x) = (x .: "objectClass" >>= toMedia) <*> x .: "title"
-}

最后但同样重要的是,请记住 valid JSON使用字符串作为名称。

关于json - Haskell::Aeson::根据字段值解析ADT,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25500871/

相关文章:

Java - 以分钟为单位计算差异

c++ - boost中的正则表达式提取信息

c++ - boost程序选项的parse_config_file如何解析multitoken

haskell - 使用解析器组合器解析 Haskell 本身

haskell - 将参数限制为 Int

ios - 如何将 String 转换为 JSON,以便我可以将其解析为对象

android json object 代码中的一些问题无法从 php 获取 json 数组

c# - 从动态 json 结果中获取列表

parsing - 左分解和左递归之间的区别

haskell - 'do' block 内的守卫 - haskell