Haskell :: Aeson ::根据字段值解析ADT [英] Haskell :: Aeson :: parse ADT based on field value

查看:74
本文介绍了Haskell :: Aeson ::根据字段值解析ADT的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



以下是我的问题的简化版本:

  newtype Content = Content {content :: [Media]}派生(通用)

实例FromJSON内容

数据媒体=
视频{objectClass :: Text
,title :: Text} |
AudioBook {objectClass :: Text
,title :: Text}

API文档据说对象可以通过字段 objectClass 来识别,它对我们的 Video 对象具有值video,我们的 AudioBook 等等。例子JSON:

  [{objectClass:video,title:Some title} 
,{objectClass: audiobook,标题:Other title}]

现在的问题是,这种类型的JSON使用Aeson吗?

  instance FromJSON Media其中
parseJSON(Object x)= ???


解决方案

您基本上需要一个函数文字 - >文字 - >媒体

  toMedia ::文字 - >文字 - > Media 
toMediavideo= Videovideo
toMediaaudiobook= AudioBookaudiobook

FromJSON 实例现在非常简单(使用< $> 和<$ c

$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ p> instance FromJSON Media其中
parseJSON(Object x)= toMedia< $> x。:objectClass*< x。:title

然而,在这一点上你是多余的:<$ c $在视频音频中的c> objectClass 字段不会提供比实际的类型,所以你可能会删除它:

  data媒体=视频{title :: Text} 
| AudioBook {title :: Text}

toMedia :: Text - >文字 - > Media
toMediavideo= Video
toMediaaudiobook= AudioBook

另请注意, toMedia 是部分内容。您可能想要捕获无效的objectClass值:

  instance FromJSON Media 
parseJSON(Object x)=
do oc< - x。:objectClass
case oc of
Stringvideo - >视频< $> x。:title
字符串audiobook - > AudioBook< $> x。:title
_ - >空

- 使用合适的媒体
替代媒体::选择f =>文字 - > f(Text - > Media)
toMediavideo=纯视频
toMediaaudiobook=纯音频书
toMedia _ =空

实例FromJSON Media其中
parseJSON(Object x)=(x。:objectClass>> = toMedia)*< x。:title
- }

最后但并非最不重要的一点,请记住有效的JSON 使用字符串作为名称。


I'm using an external API which returns JSON responses. One of the responses is an array of objects and these objects are identified by the field value inside them. I'm having some trouble understanding how the parsing of such JSON response could be done with Aeson.

Here is a simplified version of my problem:

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

instance FromJSON Content

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

In API documentation it is said that the object can be identified by the field objectClass which has value "video" for our Video object and "audiobook" for our AudioBook and so on. Example JSON:

[{objectClass: "video", title: "Some title"}
,{objectClass: "audiobook", title: "Other title"}]

The question is how can this type of JSON be approached using Aeson?

instance FromJSON Media where
  parseJSON (Object x) = ???

解决方案

You basically need a function Text -> Text -> Media:

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

The FromJSON instance is now really simple (using <$> and <*> from Control.Applicative):

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

However, at this point you're redundant: the objectClass field in Video or Audio doesn't give you more information than the actual type, so you might remove it:

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

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

Also note that toMedia is partial. You probably want to catch invalid "objectClass" values:

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"
-}

And last, but not least, remember that valid JSON uses strings for the name.

这篇关于Haskell :: Aeson ::根据字段值解析ADT的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆