matthias matthias - 5 months ago 19
JSON Question

Haskell: Dynamic object field name with aeson

If I have a data structure that takes in two values from

readFile
; how do I use those values as the fieldnames for my
toJSON
instance declaration?

For example in the code below, the names "2015" and "2016" are to change depending on the input file.

data MyOutput = MyOutput
{ periodOne :: YearInfo
, periodTwo :: YearInfo
, updateStamp :: String
} deriving (Show)

instance ToJSON MyOutput where
toJSON MyOutput {..} =
object [ "2015" .= periodOne
, "2016" .= periodTwo
, "Data up to" .= updateStamp
]

Answer

Unfortunately ToJSON instances cannot depend on values external to the data structure.

My suggestion is to change the data structure to include the field names for periodOne and periodTwo:

data MyOutput = MyOutput {
                  periodOneName, periodTwoName :: String,
                  periodOne, periodTwo :: YearInfo
                  ...
              }

Now the toJSON instance has access to the names of the periods.

Complete example:

{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE OverloadedStrings #-}

import Data.Aeson
import qualified Data.Text as T

type YearInfo = [ Int ]

data MyOutput = MyOutput
              { periodOne   :: YearInfo
              , periodTwo   :: YearInfo
              , periodOneName :: T.Text
              , periodTwoName :: T.Text
              , updateStamp :: String
              } deriving (Show)

instance ToJSON MyOutput where
  toJSON MyOutput {..} =
    object [ periodOneName .= toJSON periodOne
           , periodTwoName .= toJSON periodTwo
           , "Data up to"  .= toJSON updateStamp
           ]
Comments