我正在处理来自REST服务器的一些复杂格式的JSON响应。为了解码它们,我有几种数据类型来处理不同的嵌套对象。例如:
... Other types ...
data Profile =
Profile { fields :: [KVPair]
} deriving (Show)
instance FromJSON Profile where
parseJSON (Object v) =
Profile <$> v .: "Fields"
parseJSON _ = mzero
data KVPair =
KVPair { key :: Int
, value :: String
} deriving (Show)
instance FromJSON KVPair where
parseJSON (Object v) =
KVPair <$> v .: "Key"
<*> v .: "Value"
parseJSON _ = mzero
除最终的KVPair类型外,一切正常。我的JSON对象都有整数键;但是,值可以是整数或字符串:
{
"Key": 0,
"Value": "String Value!"
},
{
"Key": 1,
"Value": 42
}
现在我想我可以为我的值解码添加另一个和类型,它由String
和Int
组成,但我宁愿避免为此添加一个全新的类型。 Aeson有一种简单的方法来处理这种情况吗?
答案 0 :(得分:5)
有两个简单的修复方法。一个是简单地写
data KVPair = KVPair { key :: Int, value :: Value }
并保留所有其他代码相同。消费者需要检查Value
以查看它是字符串还是数字。
可能更好的方法是简单地提供两个可转换为所需格式的替代解析器。例如,保持KVPair
定义不变,可以写
showInt :: Int -> String
showInt = show
instance FromJSON KVPair where
parseJSON (Object v)
= KVPair
<$> v .: "Key"
<*> (v .: "Value" <|> (showInt <$> v .: "Value"))
两个方面最好的方法是保留关于和周围的String
或Int
以拒绝其他类型值的信息; e.g。
data KVPair = KVPair { key :: Int, value :: Either String Int }
instance FromJSON KVPair where
parseJSON (Object v)
= KVPair
<$> v .: "Key"
<*> ( (Left <$> v .: "Value")
<|> (Right <$> v .: "Value")
)
答案 1 :(得分:1)
您只需使用Aeson Value类型来处理具有可以是任何JSON值的字段的对象。