使用包含保留关键字的字段名解析JSON

时间:2013-08-23 19:43:40

标签: haskell aeson

我正在尝试用aeson解析以下JSON。

{
    "data": [
        {
            "id": "34",
            "type": "link",
            "story": "foo"
        },
        {
            "id": "35",
            "type": "link",
            "story": "bar"
        }
    ]
}

由于我想忽略很多字段,所以似乎I should use GHC generics。但是如何编写使用Haskell关键字的数据类型定义,如datatype?以下当然是:parse error on input `data'

data Feed = Feed {data :: [Post]}
    deriving (Show, Generic)

data Post = Post {
        id :: String,
        type :: String,
        story :: String
    }
    deriving (Show, Generic)

2 个答案:

答案 0 :(得分:13)

您可以编写自己的FromJSONToJSON实例,而无需依赖GHC.Generics。这也意味着您可以为数据表示和JSON表示使用不同的字段名称。

Post的示例实例:

{-# LANGUAGE OverloadedStrings #-}
import Control.Applicative
import Data.Aeson
import qualified Data.ByteString.Lazy as LBS

data Post = Post {
        postId :: String,
        typ :: String,
        story :: String
  }
  deriving (Show)

instance FromJSON Post where
  parseJSON (Object x) = Post <$> x .: "id" <*> x.: "type" <*> x .: "story"
  parseJSON _ = fail "Expected an Object"

instance ToJSON Post where
  toJSON post = object 
    [ "id" .= postId post
    , "type" .= typ post
    , "story" .= story post
    ]

main :: IO ()
main = do
  print $ (decode $ Post "{\"type\": \"myType\", \"story\": \"Really interresting story\", \"id\" : \"SomeId\"}" :: Maybe Post)
  LBS.putStrLn $ encode $ Post "myId" "myType" "Some other story"

Feed也可以这样做。如果您不必忽略字段,也可以使用deriveJSON中的Data.Aeson.TH,{{1}}采用函数修改字段名称作为第一个参数。

答案 1 :(得分:0)

要将@bennofs 方法与泛型结合起来,您可以参考 Aeson: the tutorial 中的示例:

{-# LANGUAGE DeriveGeneric #-}

import GHC.Generics
import Data.Aeson
import Data.Aeson.Types

data Person = Person {
  _name :: String,
  _age  :: Int }
  deriving (Generic)

instance ToJSON Person where
  toJSON = genericToJSON defaultOptions {
             fieldLabelModifier = drop 1 }

instance FromJSON Person where
  parseJSON = genericParseJSON defaultOptions {
                fieldLabelModifier = drop 1 }

同时将 fieldLabelModifier 设置为仅替换所需的标签:

keywordFieldLabelModifier "_id" = "id"
keywordFieldLabelModifier "_type" = "type"
keywordFieldLabelModifier = id