2012-01-06 4 views
4

Je veux analyser un objet JSON et créer un JSONEvent avec la donnée name et argsParsing un tableau imbriqué d'objets avec Aeson

J'utilise Aeson, et je suis en ce moment stucked sur la conversion à un "args":[{"a": "b"}][(String, String)].

Merci d'avance!

{-# 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 

Répondre

3

est ici un peu plus complexe par exemple basé sur l'exemple de ehird. Notez que le typage explicite sur les appels à parseJSON est inutile mais je les trouve utiles à des fins de documentation et de débogage. Aussi je ne suis pas sûr de ce que vous aviez l'intention, mais avec args avec de multiples valeurs que je concaténer simplement tous les args ensemble comme ceci:

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

Voici le 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 p s = do 
    value <- P.eitherResult $ (P.parse json . S.fromString) s 
    DAT.parseEither p value 
3

Je ne suis pas un expert en Aeson, mais si vous avez Object o, puis o est tout simplement un HashMap Text Value; vous pouvez utiliser Data.HashMap.Lazy.toList pour le convertir en [(Text, Value)], et Data.Text.unpack pour convertir le Text en String s.

Donc, vous pourriez probablement écrire:

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 
+0

Je ne vraiment obtenir ce qui se passe sur. Je suis assez nouveau chez Haskell .. C'est ce que j'ai: – masylum

+0

http://hpaste.org/56163 – masylum

+0

@masylum: Ah, j'ai mal interprété votre code. Voulez-vous que l'analyse échoue si, par ex. vous avez '' "args": [{"a": "b", "c": d "}]', c'est-à-dire un objet avec plus d'une clé dans la liste? oublié le 'import Control.Arrow'. – ehird