oddbit
oddbit

Reputation: 25

Haskell Aeson Parse Mixed Elements Array

I have a json like:

{
  "name" : "Sam",
  "items": [ "sword", "shield", [] ]
}

and a data type

data Adventurer = Adventurer {
  name :: String,
  items :: [String]
} deriving (Generic, Show, FromJSON, ToJSON)

The problem is caused by the fact that the "items" field has the extra [] in the array and I get "expected String, encountered Array".

I've been trying to fix this with custom data types for the elements of the "items" array, or trying make a custom parser to ignore the extra array.

Is there a way to parse an array and only take the items which are of a certain type, dropping the rest?

Upvotes: 2

Views: 315

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476503

Yes, we can for example first construct a function that maps Values (these are JSON objects) to Maybe Strings:

import Data.Aeson(Value(String))
import Data.Text(unpack)

getString :: Value -> Maybe String
getString (String t) = Just (unpack t)
getString _ = Nothing

We can then define a custom implementation of FromJOSN for Adventurer like:

{-# LANGUAGE OverloadedStrings #-}

import Data.Aeson(FromJSON(parseJSON), withObject, (.:))
import Data.Maybe(catMaybes)

instance FromJSON Adventurer where
    parseJSON = withObject "Adventurer" $ \v -> Adventurer
        <$> v .: "name"
        <*> fmap (catMaybes . map getString) (v .: "items")

This then yields for example:

Main> t = "{\n  \"name\" : \"Sam\",\n  \"items\": [ \"sword\", \"shield\", [] ]\n}"
Main> decode t :: Maybe Adventurer 
Just (Adventurer {name = "Sam", items = ["sword","shield"]})

Upvotes: 2

Related Questions