Parse a nested array of objects using Aeson

I want to parse a JSON object and create a JSONEvent with data name and args

I use Aeson, and now I'm fixated on converting "args":[{"a": "b"}] to [(String, String)] .

Thanks in advance!

 {-# LANGUAGE OverloadedStrings #-} import Control.Applicative import Data.Aeson data JSONEvent = JSONEvent [(String, String)] (Maybe String) deriving Show instance FromJSON JSONEvent where parseJSON j = do o <- parseJSON j name <- o .:? "name" args <- o .:? "args" .!= [] return $ JSONEvent args name let decodedEvent = decode "{\"name\":\"edwald\",\"args\":[{\"a\": \"b\"}]}" :: Maybe JSONEvent 
+4
source share
2 answers

Here is a slightly more complex example based on the ehird example. Note that explicit spelling when calling parseJSON is not necessary, but I find them useful for documentation and debugging. Also I'm not sure what you intended, but with args with multiple values, I just concatenate all args together like this:

 *Main> decodedEvent2 Just (JSONEvent [("a","b"),("c","d")] (Just "edwald")) *Main> decodedEvent3 Just (JSONEvent [("a","b"),("c","d")] (Just "edwald")) 

Here is the code:

 {-# LANGUAGE OverloadedStrings #-} import Control.Applicative import qualified Data.Text as T import qualified Data.Foldable as F import qualified Data.HashMap.Lazy as HM import qualified Data.Vector as V import Data.Aeson import qualified Data.Attoparsec as P import Data.Aeson.Types (Parser) import qualified Data.Aeson.Types as DAT import qualified Data.String as S data JSONEvent = JSONEvent [(String, String)] (Maybe String) deriving Show instance FromJSON JSONEvent where parseJSON = parseJSONEvent decodedEvent = decode "{\"name\":\"edwald\",\"args\":[{\"a\": \"b\"}]}" :: Maybe JSONEvent decodedEvent2 = decode "{\"name\":\"edwald\",\"args\":[{\"a\": \"b\"}, {\"c\": \"d\"}]}" :: Maybe JSONEvent decodedEvent3 = decode "{\"name\":\"edwald\",\"args\":[{\"a\": \"b\", \"c\": \"d\"}]}" :: Maybe JSONEvent emptyAesonArray :: Value emptyAesonArray = Array $ V.fromList [] parseJSONEvent :: Value -> Parser JSONEvent parseJSONEvent v = case v of Object o -> do name <- o .:? "name" argsJSON <- o .:? "args" .!= emptyAesonArray case argsJSON of Array m -> do parsedList <- V.toList <$> V.mapM (parseJSON :: Value -> Parser (HM.HashMap T.Text Value)) m let parsedCatList = concatMap HM.toList parsedList args <- mapM (\(key, value) -> (,) <$> (return (T.unpack key)) <*> (parseJSON :: Value -> Parser String) value) parsedCatList return $ JSONEvent args name _ -> fail ((show argsJSON) ++ " is not an Array.") _ -> fail ((show v) ++ " is not an Object.") -- Useful for debugging aeson parsers decodeWith :: (Value -> Parser b) -> String -> Either String b decodeWith ps = do value <- P.eitherResult $ (P.parse json . S.fromString) s DAT.parseEither p value 
+3
source

I'm not an expert on eson, but if you have Object o , then o is just a HashMap Text Value ; you can use Data.HashMap.Lazy.toList to convert it to [(Text, Value)] , and Data.Text.unpack to convert Text to String s.

So, presumably you could write:

 import Control.Arrow import Control.Applicative import qualified Data.Text as T import qualified Data.Foldable as F import qualified Data.HashMap.Lazy as HM import Data.Aeson instance FromJSON JSONEvent where parseJSON j = do o <- parseJSON j name <- o .:? "name" Object m <- o .:? "args" .!= [] args <- map (first T.unpack) . HM.toList <$> F.mapM parseJSON m return $ JSONEvent args name 
+3
source

Source: https://habr.com/ru/post/1389681/


All Articles