用Aeson解析有问题的JSON
我试图解析JSON对象,这些对象通常是用Aeson解析有问题的JSON,json,haskell,aeson,Json,Haskell,Aeson,我试图解析JSON对象,这些对象通常是 { "objects": [a bunch of records that can assume a few different forms], "parameters": [same deal], "values": { "k1": "v1", "k2": "v2", ... } } 使用Haskell的Aeson库。这项任务的一部分
{
"objects": [a bunch of records that can assume a few different forms],
"parameters": [same deal],
"values": {
"k1": "v1",
"k2": "v2",
...
}
}
使用Haskell的Aeson库。这项任务的一部分很简单,因为参数
和值
字段不需要任何自定义解析(因此似乎只需要从JSON派生的实例),与对象相关联的数组中包含的大多数记录也不需要特殊解析。然而,在分析对象数组中的记录时,有一些部分单独考虑时,它们有文档化的解决方案,但它们一起提出了一些问题,我还没有弄清楚如何解决这些问题
现在,对象
和参数
数组中记录的可能变体数量有限,通常包含相同的键;例如,它们都有一个“name”键或一个“id”键,等等。但它们中的许多都有一个“type”键,这是一个保留关键字,因此不能进行一般性的解析。这是第一个问题
第二个问题是,对象中记录的一个可能变体可以有一个键--“depends”,比如说--其值可以采用不同的类型。它可以是单个记录
{
"objects": [
{
"depends": {
"reference": "r1"
},
...
],
...
}
或者一份记录清单
{
"objects": [
"depends": [
{"reference": "r1"},
{"reference": "r2"},
etc.
],
],
...
}
在转换为Haskell对象后,我希望以自定义方式处理这个字段(最终我希望将此类“依赖”引用的集合表示为Data.Graph
Graph)
我最初的尝试是创建一个巨大的记录类型,它包含对象
和参数
数组元素中所有可能的键。大概是这样的:
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
import Data.Aeson
import GHC.Generics
data Ref = Ref
{ ref :: String
} deriving (Show, Generic, FromJSON, ToJSON)
data Reference
= Reference Ref
| References [Ref]
deriving (Show, Generic, FromJSON, ToJSON)
type MString = Maybe String -- I'm writing this a lot using this approach
data PObject = PObject
-- Each of the object/parameter records have these keys
{ _name :: String
, _id :: String
-- Other keys that might appear in a given object/parameter record
, _type :: MString
, _role :: MString
, _depends :: Maybe Reference
-- A bunch more
} deriving Show
instance FromJSON PObject where
parseJSON = withObject "PObject" $ \o -> do
_name <- o .: "name"
_id <- o .: "id"
_type <- o .:? "type"
_role <- o .:? "role"
_depends <- o .:? "depends"
-- etc.
return PObject{..}
直到它试图解析一个“depends”字段,并报告
"Error in $.objects[2].depends: key \"tag\" not present"
没有“标记”键,所以我不确定这意味着什么。我怀疑这与Ref
和Reference
的FromJSON
的通用实例有关
我的问题:
这个错误表示什么?到目前为止,在我对Haskell的学习中,这些错误总是非常有用的。这个不是。我是否需要为我的parseJSON
函数中的“depends”键做一些特殊的操作
所有这些样板都是因为两个键--“type”和“depends”。有没有更优雅的方法来处理这些钥匙
相关地,这是我第一个真正的Haskell项目的一部分,所以我有一个更一般的设计问题。有经验的Haskellers和Aeson用户,您将如何为这种类型的JSON布局您的类型和实例?我尝试将对象的每个可能变体
/参数
记录列为其自己的单独类型,并且只为那些具有“depends”或“type”键的对象编写自定义FromJSON
实例,但这产生了更多的样板代码,并且在任何情况下都无法解决我遇到的任何其他问题。关于“最佳实践”、惯用用法等的一般性指南将非常有用并受到赞赏李>
没有“标记”键,所以我不确定这意味着什么。我怀疑这与Ref
和Reference
的FromJSON
的通用实例有关
这是正确的。aeson将使用对和类型进行编码<代码>引用
是一种总和类型。因此,aeson引入了一个标记来区分构造函数。您可以通过一个简短的示例来尝试:
ghci> data Example = A () | B deriving (Generic,ToJSON)
ghci> encode B
"{\"tag\":\"B\",\"contents\":[]}"
何时使用\u取决于
所有这些样板都是因为两个键--“type”和
“视情况而定”。有没有更优雅的方法来处理这些钥匙
您可以将下划线保留在字段名中,并在数据类型中使用,以便将其剥离以进行解析。尝试将其归结为一个问题。您的第三个问题可以在代码运行后立即得到回答。
ghci> data Example = A () | B deriving (Generic,ToJSON)
ghci> encode B
"{\"tag\":\"B\",\"contents\":[]}"