2015-12-03 1 views
0

Je suis en train d'analyser le JSON de vide sanitaire avec aseon:Comment analyser JSON imbriqué, qui contient également des listes, dans Haskell?

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" 
     } 
     ] 
    } 
    ] 
} 

J'ai essayé de mettre en place les structures de données et les instances: Voici ce que j'ai jusqu'à présent:

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) 

Mes problèmes sont que je ne sais pas comment lier les valeurs imbriquées et je ne peux comprendre comment gérer les parties de la liste des JS SUR. J'ai essayé de passer en revue la documentation et d'autres questions de stackoverflow; Cependant, je ne trouve rien pour aider à ce niveau de complexité.

Comment procéder pour obtenir des objets pour les valeurs imbriquées et pour les valeurs répertoriées.

Merci

Répondre

2

Il vous suffit de terminer la rédaction de tous les FromJSON cas pour chaque type, bien que vous devez corriger votre instance pour Body et chaque définition parseJSON doit être fonctions au total, afin d'inclure un cas lorsque vous sont donnés autre chose qu'un 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 

Ensuite, il vous suffit d'écrire chacun des parseurs pour vos autres 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 

Et ainsi de suite. Je vais vous laisser finir tous les différents types que vous avez ici. Une dernière petite note, il semble que vous ayez eu une erreur de copier/coller avec votre fichier JSON exemple, les lignes 4 et 48 nécessitent des virgules à la fin pour en faire un document JSON valide. Vous pouvez également inclure l'extension de langue DeriveGeneric, puis avec une importation de GHC.Generics vous pouvez deriving (Show, Generic) pour chacun de vos types. Ensuite, tout ce que vous devez écrire est

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 

sans avoir à spécifier les détails réels de conversion à partir de JSON. Le seul problème est maintenant que vous avez besoin du JSON pour utiliser les clés "idd" au lieu de "id" pour les structures Body, bien que je recommanderais de le renommer "bodyId" de toute façon puisque id est une fonction intégrée dans Haskell (et de même avec les autres types qui ont un champ id). Vous pouvez alors avoir instance ToJSON <type> where pour chacun de vos types afin d'obtenir automatiquement la sérialisation de vos types.

+0

je vous remercie pour votre réponse. J'ai essayé votre code avec le JSON modifié: 'decode json :: Maybe Body' = ** Nothing **. Qu'est-ce que je fais mal? – matthias

+0

@matthias Essayez 'decode json :: Maybe Response', parce que votre document JSON contient une' Response' qui contient plusieurs 'Body's. – bheklilr

+0

oui cela fonctionne. Est-ce que je ne peux pas accéder directement aux autres objets? – matthias