json parsing in haskell json parsing in haskell json json

json parsing in haskell


The problem is that Text.JSON does not know how to convert JSON data toyour Person data type. To do this, you need to either make Person andinstance of the JSON typeclass, or your can use Text.JSON.Generic and theDeriveDataTypeable extension to do the work for you.

Generics

The Text.JSON.Generic method will read the JSON structure based on thestructure of your data type.

{-# LANGUAGE DeriveDataTypeable #-}import           Text.JSON.Genericdata Address = Address    { house  :: Integer    , street :: String    , city   :: String    , state  :: String    , zip    :: Integer    } deriving (Show, Data, Typeable)data Person = Person    { name    :: String    , age     :: Integer    , address :: Address    } deriving (Show, Data, Typeable)aa :: Stringaa = "{\"name\": \"some body\", \"age\" : 23, \"address\" : {\"house\" : 285, \"street\" : \"7th Ave.\", \"city\" : \"New York\", \"state\" : \"New York\", \"zip\" : 10001}}"main = print (decodeJSON aa :: Person)

This method works really well as long as you don't mind matching the names of the fieldsin your data structure to your JSON format.

As an aside, you don't need to write functions like getName, getAddress,and getState. The names of the field in your record type are accesorfunctions.

∀ x. x ⊦ :t househouse :: Address -> Integer∀ x. x ⊦ :t addressaddress :: Person -> Address

JSON Instance

Alternatively, you could take the high road and implement your own instance ofthe JSON class.

import           Control.Applicativeimport           Control.Monadimport           Text.JSONdata Address = Address    { house  :: Integer    , street :: String    , city   :: String    , state  :: String    -- Renamed so as not to conflict with zip from Prelude    , zipC   :: Integer    } deriving (Show)data Person = Person    { name    :: String    , age     :: Integer    , address :: Address    } deriving (Show)aa :: Stringaa = "{\"name\": \"some body\", \"age\" : 23, \"address\" : {\"house\" : 285, \"street\" : \"7th Ave.\", \"city\" : \"New York\", \"state\" : \"New York\", \"zip\" : 10001}}"-- For convenience(!) :: (JSON a) => JSObject JSValue -> String -> Result a(!) = flip valFromObjinstance JSON Address where    -- Keep the compiler quiet    showJSON = undefined    readJSON (JSObject obj) =        Address        <$>        obj ! "house"  <*>        obj ! "street" <*>        obj ! "city"   <*>        obj ! "state"  <*>        obj ! "zip"    readJSON _ = mzeroinstance JSON Person where    -- Keep the compiler quiet    showJSON = undefined    readJSON (JSObject obj) =        Person       <$>        obj ! "name" <*>        obj ! "age"  <*>        obj ! "address"    readJSON _ = mzeromain = print (decode aa :: Result Person)

This takes advantage of the fact that the Result type is an Applicative to easilychain together queries on the JSObject value.

This is a little more work, but it gives you more control of the structure ofthe JSON if you have to deal with JSON that will cause style guidelineviolations due to weird field names.


Maybe a bit late in the game, but since this is the first page google returns I'll give it a go.

Aeson is the defacto standard these days so that's the library everybody uses. The Aeson TH package offers some nice functionality for automatically generating the necessary functions for your custom data types.

Basically you create your data types that correspond to the json data and then let aeson do the magic.

{-# LANGUAGE OverloadedStrings,TemplateHaskell #-}import Data.Aesonimport Data.Aeson.THimport qualified Data.ByteString.Lazy.Char8 as BLdata Address = Address    { house  :: Integer    , street :: String    , city   :: String    , state  :: Maybe String    , zip    :: Integer    } deriving (Show, Eq)data Person = Person    { name    :: String    , age     :: Integer    , address :: Address    } deriving (Show, Eq)$(deriveJSON defaultOptions ''Address)$(deriveJSON defaultOptions ''Person)aa :: BL.ByteStringaa = "{\"name\": \"some body\", \"age\" : 23, \"address\" : {\"house\" : 285, \"street\" : \"7th Ave.\", \"city\" : \"New York\", \"state\" : \"New York\", \"zip\" : 10001}}"main = print (decode aa :: Maybe Person)

You can even have optional fields with the Maybe datatype.