如何使用Aeson解析JSON值,Aeson可以是两种不同类型之一

问题描述 投票:1回答:1

我目前正在努力使用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

haskell aeson
1个回答
1
投票

解决此问题的一种方法是在对数据集有效的JSON数据构造函数上进行模式匹配,并对所有其他构造函数进行无效。

例如,您可以为该特定字段编写类似的内容,请记住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个)和基础数据结构(例如HashMapObjectVectorArray)。

例如,在上面,当你在Array arr上模式匹配时,你必须意识到你在Vector Value那里得到了一个arr,我们还有一些工作要把它变成一个整数列表,这就是为什么我留下其他功能parseListOfInt未定义上面因为我认为它可能是一个很好的练习来构建它?

© www.soinside.com 2019 - 2024. All rights reserved.