Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
用Aeson解析有问题的JSON_Json_Haskell_Aeson - Fatal编程技术网

用Aeson解析有问题的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库。这项任务的一部分

我试图解析JSON对象,这些对象通常是

{
  "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\":[]}"