如何解析 Haskell 中嵌套的 JSON,其中还包含列表?

How to parses nested JSON, which also contains lists,in Haskell?

我正在尝试用 aseon 解析休闲 JSON:

JSON

{
  "response": [
    {
      "id": 5555,
      "brandId": 10,
      "productTypeId": 1,
      "identity": {
        "sku": "ABCDEF",
        "ean": "1111",
        "barcode": "2222"
      },
      "productGroupId": 17,
      "stock": {
        "stockTracked": true,
        "weight": {
          "magnitude": 0
        },
        "dimensions": {
          "length": 0,
          "height": 0,
          "width": 0,
          "volume": 0
        }
      },
      "financialDetails": {
        "taxable": false,
        "taxCode": {
          "id": 7,
          "code": "T1"
        }
      },
      "variations": [
        {
          "optionId": 1,
          "optionName": "option1",
          "optionValueId": 5,
          "optionValue": "5"
        },
        {
          "optionId": 2,
          "optionName": "option2",
          "optionValueId": 14,
          "optionValue": "OS"
        }
      ]
    },
    {
      "id": 9999,
      "brandId": 10,
      "productTypeId": 1,
      "identity": {
        "sku": "CDEFG",
        "ean": "111221",
        "barcode": "2443222"
      },
      "productGroupId": 17,
      "stock": {
        "stockTracked": true,
        "weight": {
          "magnitude": 0
        },
        "dimensions": {
          "length": 0,
          "height": 0,
          "width": 0,
          "volume": 0
        }
      },
      "financialDetails": {
        "taxable": false,
        "taxCode": {
          "id": 7,
          "code": "T1"
        }
      },
      "variations": [
        {
          "optionId": 1,
          "optionName": "option1",
          "optionValueId": 5,
          "optionValue": "5"
        },
        {
          "optionId": 2,
          "optionName": "option2",
          "optionValueId": 14,
          "optionValue": "14"
        }
      ]
    } 
  ]
}

我已尝试设置数据结构和实例:这是我目前所拥有的:

代码

{-# LANGUAGE OverloadedStrings #-}

import Data.Aeson 
import Control.Applicative 
import qualified Data.ByteString.Lazy.Char8 as BS



data Response = Response                    { response              :: [Body]
                                            } deriving (Show)

instance FromJSON Response where
    parseJSON (Object v) = Response <$>
                           v .: "response"                                             

data Body = Body                            { idd                   :: Int
                                            , brandId               :: Int
                                            , productTypeId         :: Int
                                            , identity              :: Identity
                                            , productGroupId        :: Int
                                            , stock                 :: Stock
                                            , financialDetails      :: FinancialDetails
                                            , variations            :: [Variation]
                                            } deriving (Show)

instance FromJSON Body where
    parseJSON (Object v) = Body <$>
                           (e >>= (.: "id")) <*>
                           (e >>= (.: "brandId")) <*>
                           (e >>= (.: "productTypeId")) <*>
                         -- DON'T KNOW HOW TO SET UP  IDENTITY  
                           (e >>= (.: "productGroupId"))
                         -- DON'T KNOW HOW TO SET UP STOCK  
                         -- DON'T KNOW HOW TO SET UP FINANCIAL DETAILS                          
                         -- DON'T KNOW HOW TO SET UP VARIATIONS  
                           where e = (v .: "response")                                              


data Identity = Identity                    { sku                   :: String
                                            , ean                   :: String
                                            , barcode               :: String 
                                            } deriving (Show)

data Stock = Stock                          { stockTracked          :: Bool
                                            , weight                :: Weight
                                            , dimensions            :: Dimensions
                                            } deriving (Show)

data Weight = Weight                        { magnitude             :: Double
                                            } deriving (Show)

data Dimensions = Dimensions                { length                :: Double
                                            , height                :: Double
                                            , width                 :: Double
                                            , volume                :: Double  
                                            } deriving (Show)       

data FinancialDetails = FinancialDetails    { taxable               :: Bool
                                            , taxCode               :: TaxCode
                                            } deriving (Show)

data TaxCode = TaxCode                      { id                    :: Int
                                            , code                  :: String
                                            } deriving (Show)    


data Variation = Variation                  { optionId              :: Int
                                            , optionName            :: String
                                            , optionValueId         :: Int
                                            , optionValue           :: String
                                            }  deriving (Show)  

我的问题是我不知道如何绑定嵌套值,也不知道如何处理 JSON 的列表部分。我试图通过文档和其他 Whosebug 问题;但是我找不到任何可以帮助解决这种复杂程度的方法。

我将如何为嵌套值和列出的值获取对象。

谢谢

您只需要完成为每个类型编写所有 FromJSON 个实例,尽管您需要为 Body 修复您的实例并且 parseJSON 的每个定义都应该是总函数, 所以包括一个案例,当你得到的不是 Object:

data Response = Response
    { response :: [Body]
    } deriving (Show)

instance FromJSON Response where
    parseJSON (Object v) = Response <$> v .: "response"
    parseJSON _ = mzero

data Body = Body
    { idd               :: Int
    , brandId           :: Int
    , productTypeId     :: Int
    , identity          :: Identity
    , productGroupId    :: Int
    , stock             :: Stock
    , financialDetails  :: FinancialDetails
    , variations        :: [Variation]
    } deriving (Show)

instance FromJSON Body where
    parseJSON (Object v) = Body
        <$> v .: "id"
        <*> v .: "brandId"
        <*> v .: "productTypeId"
        <*> v .: "identity"
        <*> v .: "productGroupId"
        <*> v .: "stock"
        <*> v .: "financialDetails"
        <*> v .: "variations"
    parseJSON _ = mzero

然后你只需要为你的其他类型编写每个解析器:

data Identity = Identity
    { sku       :: String
    , ean       :: String
    , barcode   :: String
    } deriving (Show)

instance FromJSON Identity where
    parseJSON (Object v) = Identity
        <$> v .: "sku"
        <*> v .: "ean"
        <*> v .: "barcode"
    parseJSON _ = mzero

data Stock = Stock
    { stockTracked  :: Bool
    , weight        :: Weight
    , dimensions    :: Dimensions
    } deriving (Show)

instance FromJSON Stock where
    parseJSON (Object v) = Stock
        <$> v .: "stockTracked"
        <*> v .: "weight"
        <*> v .: "dimensions"
    parseJSON _ = mzero

等等。我会让你完成这里所有的不同类型。

最后一点注意,您的示例 JSON 文件似乎有 copy/paste 错误,第 4 行和第 48 行末尾需要逗号才能使其成为有效的 JSON 文档.

或者,您可以包含 DeriveGeneric 语言扩展,然后通过导入 GHC.Generics,您可以为每个类型 deriving (Show, Generic)。那么你只需要写

instance FromJSON Response where
instance FromJSON Body where
instance FromJSON Identity where
instance FromJSON Stock where
instance FromJSON Weight where
instance FromJSON Dimensions where
instance FromJSON FinancialDetails where
instance FromJSON TaxCode where
instance FromJSON Variation where

无需指定如何从 JSON 转换的实际细节。现在唯一的问题是你需要 JSON 来使用键 "idd" 而不是 "id" 用于 Body 结构,尽管我建议将它重命名为 "bodyId" 无论如何,因为 id 是 Haskell 中的内置函数(与其他具有 id 字段的类型类似)。然后,您还可以为每个类型设置 instance ToJSON <type> where,以便自动获得类型的序列化。