Incerteza
Incerteza

Reputation: 34884

Parsing nested values in JSON

I have such an ugly part of code:

request <- parseUrl "someUrl.com"
res <- withManager $ httpLbs request
case decode $ responseBody res :: Maybe Aeson.Value of
  Just (Aeson.Object jsonObject) ->  
    case (HashMap.lookup "aaa" jsonObject) of
      Just a ->
        case a of 
          Aeson.Object jsonObject2 ->
            case (HashMap.lookup "bbb" jsonObject2) of
              Just b ->
                case b of
                  Aeson.Object jsonObject3 ->
                    case (HashMap.lookup "ccc" jsonObject3) of
                      Just c -> 
                        case c of
                          Array d -> 
                            case (d ! 1) of
                              String a  -> print a
                              _ -> error "error!!!"
                          _ -> error "error!!"
                      _ -> error "error!!"
                  _ -> error "error!!" 
              _ -> error "error!!"
          _ -> error "error!!"
      _ -> error "error!!"

_ -> error "Invalid JSON"

It does work well but it doesn't look good. How do I simplify it? I'm positive there is a way to do this. Note that I'm not using any custom data type for parsing a JSON and don't want to.

Upvotes: 3

Views: 263

Answers (2)

MigMit
MigMit

Reputation: 1697

do syntax for Maybe monad:

request <- parseUrl "someUrl.com"
res <- withManager $ httpLbs request
let toPrint =
  do Aeson.Object jsonObject <- decode $ responsBody res
     Aeson.Object jsonObject2 <- HashMap.lookup "aaa" jsonObject
     Aeson.Object jsonObject3 <- HashMap.lookup "bbb" jsonObject2
     Array d <- HashMap.lookup "ccc" jsonObject3
     String a <- return $ d ! 1
     return a
case toPrint of
    Just a -> print a
    Nothing -> "Invalid JSON"

Upvotes: 5

J. Abrahamson
J. Abrahamson

Reputation: 74354

This problem—producing deep dives into large, complex data structures, is exactly what lens seeks to solve. The idea of Lenses isn't tough, but the package lens can be scary. I've written a few tutorials on this concept, however, which may be useful

In any case, for your particular example, we can replace this nested case with something like

print $ responseBody res ^!? key "aaa" 
                         .   key "bbb"
                         .   key "ccc"
                         .   ix 1 
                         .   _String

though I would recommend avoiding things like error to indicate failure. The (^?) combinators (also called preview) would help.

Upvotes: 8

Related Questions