如何在Haskell中解析嵌套的JSON,它也包含列表?

时间:2015-12-03 16:17:16

标签: json haskell nested aeson

我试图用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"
        }
      ]
    } 
  ]
}

我试图设置数据结构和实例:这是我到目前为止所拥有的:

CODE

{-# 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的列表部分。我试图通过文档和其他stackoverflow问题;但是我找不到任何可以帮助解决这种复杂程度的问题。

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

由于

1 个答案:

答案 0 :(得分:2)

您只需完成为每种类型编写所有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文件有一个复制/粘贴错误,第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 。那么你需要写的就是

"idd"

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