Reputation: 2069
I am trying to parse the fallowing JSON with aseon:
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"
}
]
}
]
}
I have tried to set up the data structures and instances: Here is what I have so far:
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)
My problems are that I do not know how to bind the nested values nor can I figure out how to handle the list portions of the JSON. I have tried to go through the documentation and other stackoverflow questions; however I cannot find anything to help with this level of complexity.
How would I go about getting objects for the nested values and for the listed values.
Thanks
Upvotes: 0
Views: 187
Reputation: 54078
You just need to finish writing all the FromJSON
instances for each type, although you need to fix up your instance for Body
and each definition of parseJSON
should be total functions, so include a case for when you are given something other than an 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
Then you just need to write each of the parsers for your other types:
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
And so on. I'll let you finish out all the different types you have here.
One last little note, it appears as though you had a copy/paste error with your sample JSON file, lines 4 and 48 need commas at the end to make it a valid JSON document.
Alternatively, you could include the DeriveGeneric
language extension, then with an import of GHC.Generics
you can deriving (Show, Generic)
for each of your types. Then all you need to write is
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
without needing to specify the actual details of how to convert from JSON. The only problem now is that you need the JSON to use the keys "idd"
instead of "id"
for the Body
structures, although I would recommend renaming it to be "bodyId"
anyway since id
is a built-in function in Haskell (and similarly with the other types that have an id
field). You can then also have instance ToJSON <type> where
for each of your types in order to automatically get serialization of your types.
Upvotes: 2