我目前正在努力使用aeson
库解析一些JSON数据。当缺少该属性的数据时,会有许多属性具有值false
。因此,如果属性的值通常是整数数组,并且恰好没有该属性的数据,则该值是null
,而不是提供空数组或false
。 (该数据的结构方式不是我要做的,因此我将不得不以某种方式使用它。)
理想情况下,如果值是布尔值,我想以一个空列表结尾。我在下面创建了一个小测试用例进行演示。因为我的Group
数据构造函数需要一个列表,所以遇到false
时它无法解析。
data Group = Group [Int] deriving (Eq, Show)
jsonData1 :: ByteString
jsonData1 = [r|
{
"group" : [1, 2, 4]
}
|]
jsonData2 :: ByteString
jsonData2 = [r|
{
"group" : false
}
|]
instance FromJSON Group where
parseJSON = withObject "group" $ \g -> do
items <- g .:? "group" .!= []
return $ Group items
test1 :: Either String Group
test1 = eitherDecode jsonData1
-- returns "Right (Group [1,2,4])"
test2 :: Either String Group
test2 = eitherDecode jsonData2
-- returns "Left \"Error in $.group: expected [a], encountered Boolean\""
最初,我希望(.!=)
运算符允许它默认为一个空列表,但只有在该属性完全不存在或null
时才可以使用。如果它是"group": null
,它将成功解析,而我将得到Right (Group [])
。
在false
的情况下,如何获得成功解析并返回空列表的任何建议?
答案 0 :(得分:1)
解决此问题的一种方法是在对您的数据集有效的 JSON数据构造函数上进行模式匹配,并对所有其他数据集抛出 invalid 。
例如,您可以为该特定字段编写类似的代码,请记住parseJSON
是Value -> Parser a
中的函数:
instance FromJSON Group where
parseJSON (Bool False) = Group <$> pure []
parseJSON (Array arr) = pure (Group $ parseListOfInt arr)
parseJSON invalid = typeMismatch "Group" invalid
parseListOfInt :: Vector Value -> [Int]
parseListOfInt = undefined -- build this function
您可以在Aeson docs中看到一个示例,该示例非常好(但是您必须仔细阅读它们并进行几次阅读)。
然后我可能会定义一个单独的记录来表示此密钥进入并依赖于泛型派生的顶级对象,但是其他人可能会有更好的建议:
data GroupObj = GroupObj { group :: Group } deriving (Eq, Show)
instance FromJSON GroupObj
使用Aeson时要牢记的一件事是core constructors(只有6个)和基础数据结构(HashMap
和{{1 }},例如Object
。
例如,在上面的示例中,当您在Vector
上进行模式匹配时,您必须知道在Array
中有一个Array arr
在那里,我们还有一些工作要做这样做以将其转换为整数列表,这就是为什么我在上面未定义其他函数Vector Value
的原因,因为我认为构建它可能是一个好练习?