I have the below code for parsing Int from an object. But unable to find the correct import for Key.
parseInt :: Object -> Key -> Parser Int
parseInt v field =
asum
[ v .: field,
do
s <- v .: field
case readMaybe s :: Maybe Int of
Nothing -> fail "not a number"
Just x -> return x
]
I have tried
import Data.Aeson
and
import Data.Aeson.Types
But get the error
Not in scope: type constructor or class ‘Key’
A data constructor of that name is in scope; did you mean DataKinds?
What should be the correct import for Key in my function?
It looks like you're writing code targeting aeson 2.x, but that you have aeson 1.x installed. Either upgrade (recommended), or use Text in place of Key there.
Related
I need to parse iCalendar format, which is basically what is used by Google Calendar and almost all calendar apps.
I have found this package iCalendar Hackage
But I cannot figure out how to use the parseICalendar function in this package, if someone can tell me what I am doing wrong, it would be great.
Mainly I cannot figure out how to construct an argument for the Type DecodingFunctions
parseICalendar :: DecodingFunctions
-> FilePath -- ^ Used in error messages.
-> ByteString
-> Either String ([VCalendar], [String])
My effort:
module CalendarReader
( getCalendar
, getSummary
) where
{-# LANGUAGE OverloadedStrings #-}
import qualified Data.ByteString.Lazy as B -- package "bytestring"
import qualified Text.ICalendar as ICal -- package "iCalendar"
import qualified Data.Map as Map -- package "containers"
import Network.HTTP.Simple -- package "http-conduit"
import qualified Time -- local module
import Constants
getCalendar :: IO B.ByteString
getCalendar = do
request <- parseRequest $ "GET" ++ calendarURL
response <- httpLBS request
return $ getResponseBody response
getSummary :: B.ByteString -> Time.DateTime -> Int -> String
getSummary cal dateTime dayOffset = summary
where
summary = "Event Summary"
((ICal.VCalendar { ICal.vcEvents = vcEvents' }), _) = ICal.parseICalendar ?missingArgument? logFile cal
DecodingFunctions is supposed to contains a function to convert your ByteString (binary array) to a Text (representing a string of unicode characters) and one to do the same to a case-insensitive representation (for comparison purpose I suppose). If your iCalendar is "normal" and is encoded in utf-8, you can simply use the Default instance of DecodingFunctions :
parseICalendar def logFile cal
(don't forget to import def from somewhere)
If your iCalendar is not in Utf-8, you'll have to use a decode... function from Data.Text.Lazy.Encoding and mk from Data.CaseInsensitive. For Utf16 you would have :
decodings = DecodingFunctions decodeUtf16LE (mk . decodeUtf16LE)
with the right imports.
I'm trying to get a simple Json parser up and running in my Haskell code, I came across Data.Aeson which seemed like a viable solution to my problem
I followed the example code on the page, and with some minor modifications, here's what I got:
{-#LANGUAGE OverloadedStrings #-}
import Data.Aeson
import Data.Text
import Control.Applicative
import Control.Monad
data Person =
Person { firstName :: Text
, lastName :: Text
, age :: Int
} deriving Show
instance FromJSON Person where
parseJSON (Object v) =
Person <$> v .: "f_name"
<*> v .: "l_name"
<*> v .: "age"
parseJSON _ = mzero
Running the following in GHCi causes the nasty message in the title to appear:
decode "{\"f_name\":\"Haskell\", \"l_name\":\"Curry\",\"age\":114}" :: Maybe Person
So, does anyone here have an idea what went wrong? I followed the example code almost exactly as it was written, so why is it that it fails?
Before calling decode in ghci, you need to do :set -XOverloadedStrings, so the string literal is treated as a ByteString instead of a String. The pragma in the module only applies to the code in the module, not to what you do in ghci.
I'm following the Aeson library documentation but their example doesn't seem to work for me:
Code:
{-# LANGUAGE OverloadedStrings #-}
import Data.Text
import Data.Aeson
import Control.Applicative ((<$>),(<*>))
import Control.Monad
instance FromJSON Person where
parseJSON (Object v) = Person <$>
v .: "name" <*>
v .: "age"
-- A non-Object value is of the wrong type, so fail.
parseJSON _ = mzero
data Person = Person
{ name :: Text
, age :: Int
} deriving Show
Error report:
ghci> decode "{\"name\":\"Joe\",\"age\":12}" :: Maybe Person
Couldn't match expected type `Data.ByteString.Lazy.Internal.ByteString'
with actual type `[Char]'
In the first argument of `decode', namely
`"{\"name\":\"Joe\",\"age\":12}"'
In the expression:
decode "{\"name\":\"Joe\",\"age\":12}" :: Maybe Person
In an equation for `a':
a = decode "{\"name\":\"Joe\",\"age\":12}" :: Maybe Person
Am i doing something wrong here ?
The problem is that decode expects a ByteString and you are passing a String.
Try this in ghci:
:m +Data.ByteString.Lazy.Char8
decode $ pack "{\"name\":\"Joe\",\"age\":12}" :: Maybe Person
In real code you shouldn't use the Char8 module as it just truncates Chars to 8 bits without taking any account of encoding. Generally you should aim to start out with a ByteString, e.g. by reading it from disk using the functions in Data.ByteString.Lazy.
I'm having trouble finding a function or workaround to convert a String to Data.ByteString.Lazy.Internal.ByteString
One of the functions in the Aeson Json library is decode and has the following description:
decode :: FromJSON a => bytestring-0.10.0.2:Data.ByteString.Lazy.Internal.ByteString -> Maybe a
I've tried using the pack function in Data.ByteString.Lazy.Char8 but that returns a different ByteString. Any one know how this can be fixed?
The following is the example I'm working on:
import Data.Aeson
import Data.Text
import Control.Applicative
import Control.Monad (mzero)
import qualified Data.ByteString.Lazy.Internal as BLI
import qualified Data.ByteString.Lazy.Char8 as BSL
data Person = Person
{ name :: Text
, age :: Int
} deriving Show
instance FromJSON Person where
parseJSON (Object v) = Person <$>
v .: (pack "name") <*>
v .: (pack "age")
parseJSON _ = mzero
I tried using decode (BSL.pack "{\"name\":\"Joe\",\"age\":12}") :: Maybe Person
and got the following error message:
Couldn't match expected type `bytestring-0.10.0.2:Data.ByteString.Lazy.Internal.ByteString'
with actual type `BSL.ByteString'
In the return type of a call of `BSL.pack'
In the first argument of `decode', namely
`(BSL.pack "{\"name\":\"Joe\",\"age\":12}")'
In the expression:
decode (BSL.pack "{\"name\":\"Joe\",\"age\":12}") :: Maybe Person
Help!
You need to convert Char to Word8 using c2w (in Data.ByteString.Internal)
Data.ByteString.Lazy.pack $ map c2w "abcd"
I wrote out the fully qualified name for pack also to guarantee using the correct one, but you can clean this up in the imports section. When I run
> :t Data.ByteString.Lazy.pack $ map c2w "abcd"
I get ":: Data.ByteString.Lazy.Internal.ByteString"
Remember that Data.ByteString.Lazy represents strings of number values (you can't even run its pack on strings, you need to supply an array of numbers "pack [1, 2, 3, 4]"), so you might actually want to use the char equivalent Data.ByteString.Lazy.Char8.
You can also use for convenience fromString from Data.ByteString.Lazy.UTF8 from utf8-string.
It's a module of functions for the same ByteString type as aeson uses. It relyies on UTF8 as the encoding used in the buffers.
I have a server that receives JSON that looks like:
{ "foo": "bar", "bono": "bobo",
"result": { "some": ["complex", "JSON", "structure",...
}
where all the stuff is for the Server except for "result", which is to be forwarded to the client (Worker --JSON--> Server --value of "result"--> Client). Therefore, when parsing this thing with aeson, I want to keep the value of "result" as a string (or Text or whatnot), just so I can forward it to the client without caring what's inside. Problem is that "result" can be anything (array, object, etc.).
So If I do
data RPCResult = RPCResult { foo :: Text, result :: Text }
the decode function of aeson is going to return Nothing, since "result" is not necessarily a JSON string...
How do I tell aeson to keep parts of the JSON object as-is and just give them to me so I can do what I want with them?
I seem to have somewhat of a solution by making the type of result be Data.Aeson.Value and then after doing a decode on the incoming JSON, I extract the result and run encode on it before forwarding it. I'm not sure if this is the best solution (because I'm not "keeping it as a string" as the question states, but decoding it then encoding it again...) but it works:
import Data.Aeson
import Data.Maybe
import Data.ByteString.Lazy (fromStrict, ByteString)
import Data.ByteString.UTF8 (fromString)
import Control.Applicative
data RPCResult = RPCResult { foo :: Text, result :: Value }
instance FromJSON RPCResult where
parseJSON (Object v) = RPCResult <$> v .: "foo" <*> v .: "result"
-- example just so you get the idea:
toRPCResult :: String -> RPCResult
toRPCResult = fromJust . decode . fromStrict . fromString
getResult :: String -> ByteString
getResult = encode . result . toRPCResult