3

是否可以使用Text.JSON.Generic包含可选字段的 JSON 记录类型?如果我将 Haskell 类型声明为 ,我希望这会“正常工作” Maybe a,例如:

import Text.JSON.Generic

data Record = Record {
   myMandatoryField :: Integer,
   myOptionalField :: Maybe Integer
} deriving (Eq, Show, Data, Typeable)

但这并不正确。

如果无法使可选字段与 一起使用Text.JSON.Generic,是否有替代的 Haskell-JSON 数据绑定库可以与可选字段一起使用?

4

3 回答 3

7

这似乎是基于泛型的解析的一个已知问题。Aeson也遇到了同样的问题,维护人员决定弃用该功能,转而支持基于模板 Haskell 的策略:https ://github.com/bos/aeson/issues/118

使用 Aeson,您的代码看起来非常相似:

import Data.Aeson
import Data.Aeson.TH

data Record = Record {
    myMandatoryField :: Integer,
    myOptionalField :: Maybe Integer
} deriving (Eq, Show)

$(deriveJSON id ''Record)

这样,该Maybe字段按预期进行编码和解码:

$ ghci
λ :l Main.hs
Ok, modules loaded: Main.
λ encode $ Record 5 Nothing
"{\"myOptionalField\":null,\"myMandatoryField\":5}"
λ decode it :: Maybe Record
Just (Record {myMandatoryField = 5, myOptionalField = Nothing})

更新:如评论中所述,Aeson HEAD 中的 Template Haskell 可以省略空字段,但这还没有在 Hackage 上。您今天可以通过手写FromJSON/ToJSON实例获得该行为:

instance FromJSON Record where
    parseJSON = withObject "record" $ \o -> Record
        <$> o .: "myMandatoryField"
        <*> o .:? "myOptionalField"

instance ToJSON Record where
    toJSON (Record manf optf) = object $ catMaybes
        [ ("myMandatoryField" .=) <$> pure manf
        , ("myOptionalField" .=) <$> optf ]
于 2013-08-09T13:46:05.683 回答
2

通过使用新的deriveJSON :: Options -> Name -> Q [Dec]TH 生成器,您可以在 Aeson HEAD 中找到您正在寻找的行为。然后,您可以, omitNothingFields = TrueOptionsstruct中进行设置。

不确定下一个 Hackage 版本的时间表是什么。

于 2013-08-09T15:55:55.960 回答
1

为了更新J Abrahamson的答案并为了完整起见:现在可以通过派生Generic和自定义默认选项来实现该行为,如下所示:

import           GHC.Generics

data Record = Record {
  myMandatoryField :: Integer,
  myOptionalField :: Maybe Integer
} deriving (Eq, Show, Generic)

instance FromJSON Record where
    parseJSON = genericParseJSON defaultOptions { omitNothingFields  = True }
于 2017-08-31T08:55:28.087 回答