Skip to content

Instantly share code, notes, and snippets.

@reite
Last active December 17, 2015 06:49
Show Gist options
  • Save reite/5568152 to your computer and use it in GitHub Desktop.
Save reite/5568152 to your computer and use it in GitHub Desktop.
parseInvoices :: L.ByteString -> Either String [Invoice]
parseInvoices s = do
result <- eitherDecode s
flip parseEither result $ \obj -> do
d <- (obj .: "invoices") >>= (.: "invoice")
case d of
Object v -> return [v]
Array v -> return v
@reite
Copy link
Author

reite commented May 13, 2013

The structure of the json looks like this:

{"invoices":
     {"invoice": {...} or [{...}] }
}

where "invoice" will be a Array of Objects if there are more than 1 entry, or a single Object if there is only one.

@reite
Copy link
Author

reite commented May 13, 2013

Solution:

import qualified Data.Vector as V

parseObjOrArray :: (FromJSON a) => Value -> Parser a
parseObjOrArray obj = case obj of
               ob@(Object v) -> parseJSON $ Array (V.singleton ob)
               arr@(Array v) -> parseJSON arr
               _ -> error "Expected {} or []"

Use like this:

parseInvoices :: L.ByteString -> Either String [Invoice]
parseInvoices s = do
    result <- eitherDecode s
    flip parseEither result $ \obj -> (obj .: "invoices") >>= (.: "invoice") >>= parseObjOrArray

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment