Haskell Aeson json 编码字节串
Haskell Aeson json encoding bytestrings
我需要在 Haskell 中序列化一条记录,并且正在尝试使用 Aeson 来完成。问题是有些字段是 ByteString,我无法从示例中找出如何对它们进行编码。我的想法是先通过base64将它们转换成文本。这是我到目前为止的内容(我把 'undefined' 放在我不知道该做什么的地方):
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
module Main where
import qualified Data.Aeson as J
import qualified Data.ByteString as B
import qualified Data.ByteString.Base64 as B64
import qualified Data.Text as T
import qualified Data.Text.Encoding as E
import qualified GHC.Generics as G
data Data = Data
{ number :: Int
, bytestring :: B.ByteString
} deriving (G.Generic, Show)
instance J.ToJSON Data where
toEncoding = J.genericToEncoding J.defaultOptions
instance J.FromJSON Data
instance J.FromJSON B.ByteString where
parseJSON = undefined
instance J.ToJSON B.ByteString where
toJSON = undefined
byteStringToText :: B.ByteString -> T.Text
byteStringToText = E.decodeUtf8 . B64.encode
textToByteString :: T.Text -> B.ByteString
textToByteString txt =
case B64.decode . E.encodeUtf8 $ txt of
Left err -> error err
Right bs -> bs
encodeDecode :: Data -> Maybe Data
encodeDecode = J.decode . J.encode
main :: IO ()
main = print $ encodeDecode $ Data 1 "A bytestring"
如果不需要为每条记录手动定义新的 ToJSON 和 FromJSON 实例就好了,因为我有很多不同的记录,其中包含字节串。
parseJson
需要 return 类型 Parser B.ByteString
的值,因此您只需要对 [=15] 的 return 值调用 pure
=].
import Control.Monad
-- Generalized to any MonadPlus instance, not just Either String
textToByteString :: MonadPlus m => T.Text -> m B.ByteString
textToByteString = case B64.decode (E.encodeUtf8 x) of
Left _ -> mzero
Right bs -> pure bs
instance J.FromJSON B.ByteString where
parseJSON (J.String x) = textToByteString x
parseJSON _ = mzero
在这里,如果您尝试解码除 JSON 字符串以外的任何内容,并且 base-64 解码有问题,我选择 return mzero
.
同样,toJSON
只需要对您从 base64 编码的 ByteString 创建的 Text
值进行编码。
instance J.ToJSON B.ByteString where
toJSON = J.toJSON . byteStringToText
您可能要考虑使用新类型包装器,而不是直接在 B.ByteString
上定义 ToJSON
和 FromJSON
实例。
我需要在 Haskell 中序列化一条记录,并且正在尝试使用 Aeson 来完成。问题是有些字段是 ByteString,我无法从示例中找出如何对它们进行编码。我的想法是先通过base64将它们转换成文本。这是我到目前为止的内容(我把 'undefined' 放在我不知道该做什么的地方):
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
module Main where
import qualified Data.Aeson as J
import qualified Data.ByteString as B
import qualified Data.ByteString.Base64 as B64
import qualified Data.Text as T
import qualified Data.Text.Encoding as E
import qualified GHC.Generics as G
data Data = Data
{ number :: Int
, bytestring :: B.ByteString
} deriving (G.Generic, Show)
instance J.ToJSON Data where
toEncoding = J.genericToEncoding J.defaultOptions
instance J.FromJSON Data
instance J.FromJSON B.ByteString where
parseJSON = undefined
instance J.ToJSON B.ByteString where
toJSON = undefined
byteStringToText :: B.ByteString -> T.Text
byteStringToText = E.decodeUtf8 . B64.encode
textToByteString :: T.Text -> B.ByteString
textToByteString txt =
case B64.decode . E.encodeUtf8 $ txt of
Left err -> error err
Right bs -> bs
encodeDecode :: Data -> Maybe Data
encodeDecode = J.decode . J.encode
main :: IO ()
main = print $ encodeDecode $ Data 1 "A bytestring"
如果不需要为每条记录手动定义新的 ToJSON 和 FromJSON 实例就好了,因为我有很多不同的记录,其中包含字节串。
parseJson
需要 return 类型 Parser B.ByteString
的值,因此您只需要对 [=15] 的 return 值调用 pure
=].
import Control.Monad
-- Generalized to any MonadPlus instance, not just Either String
textToByteString :: MonadPlus m => T.Text -> m B.ByteString
textToByteString = case B64.decode (E.encodeUtf8 x) of
Left _ -> mzero
Right bs -> pure bs
instance J.FromJSON B.ByteString where
parseJSON (J.String x) = textToByteString x
parseJSON _ = mzero
在这里,如果您尝试解码除 JSON 字符串以外的任何内容,并且 base-64 解码有问题,我选择 return mzero
.
同样,toJSON
只需要对您从 base64 编码的 ByteString 创建的 Text
值进行编码。
instance J.ToJSON B.ByteString where
toJSON = J.toJSON . byteStringToText
您可能要考虑使用新类型包装器,而不是直接在 B.ByteString
上定义 ToJSON
和 FromJSON
实例。