像数据类型这样的默认翻译:
data Media = Video { title :: Text }
| AudioBook { title :: Text }
deriving Generic
这实际上非常接近你想要的内容。(为了简化示例,我定义了ToJSON
实例并对示例进行编码,以查看我们得到了什么类型的JSON。)
aeson, default
因此,使用默认实例(请参见完整源文件生成此输出):
[{"tag":"Video","title":"Some title"},{"tag":"AudioBook","title":"Other title"}]
让我们看看是否可以通过自定义选项来更接近...
aeson,自定义tagFieldName
使用自定义选项:
mediaJSONOptions :: Options
mediaJSONOptions =
defaultOptions{ sumEncoding =
TaggedObject{ tagFieldName = "objectClass"
-- , contentsFieldName = undefined
}
}
instance ToJSON Media
where toJSON = genericToJSON mediaJSONOptions
我们得到:
[{"objectClass":"Video","title":"Some title"},{"objectClass":"AudioBook","title":"Other title"}]
我可以翻译中文。以下是您需要翻译的内容:
(在实际代码中,你需要考虑如何处理未定义的字段。)
aeson,自定义constructorTagModifier
添加
, constructorTagModifier = fmap Char.toLower
转换为mediaJSONOptions
给出:
[{"objectClass":"video","title":"Some title"},{"objectClass":"audiobook","title":"Other title"}]
太好了! 恰好符合您的要求!
解码
只需添加具有相同选项的实例,即可从此格式进行解码:
instance FromJSON Media
where parseJSON = genericParseJSON mediaJSONOptions
例子:
*Main> encode example
"[{\"objectClass\":\"video\",\"title\":\"Some title\"},{\"objectClass\":\"audiobook\",\"title\":\"Other title\"}]"
*Main> decode $ fromString "[{\"objectClass\":\"video\",\"title\":\"Some title\"},{\"objectClass\":\"audiobook\",\"title\":\"Other title\"}]" :: Maybe [Media]
Just [Video {title = "Some title"},AudioBook {title = "Other title"}]
*Main>
完整源文件。
generic-aeson, 默认
为了获得更全面的信息,让我们也看看generic-aeson
包会提供什么(在hackage)。它还有不同于aeson
的一些方面的漂亮的默认翻译。
执行
import Generics.Generic.Aeson -- from generic-aeson package
并定义:
instance ToJSON Media
where toJSON = gtoJson
给出结果:
[{"video":{"title":"Some title"}},{"audioBook":{"title":"Other title"}}]
因此,使用aeson
时与我们所见的所有内容都不同。
generic-aeson
的选项(设置)对我们来说不是很有趣(它们只允许去掉前缀)。
(完整的源文件。)
aeson,ObjectWithSingleField
除了将构造函数名称的第一个字母小写外,generic-aeson
的翻译似乎类似于aeson
中提供的一个选项:
让我们试试这个:
mediaJSONOptions =
defaultOptions{ sumEncoding = ObjectWithSingleField
, constructorTagModifier = fmap Char.toLower
}
是的,结果是:
[{"video":{"title":"Some title"}},{"audiobook":{"title":"Other title"}}]
其余选项:(aeson,TwoElemArray
)
sumEncoding
的另一可用选项未在上述考虑范围内,因为它提供了一个与所要求的JSON表示不完全相似的数组,即TwoElemArray
。例如:
[["video",{"title":"Some title"}],["audiobook",{"title":"Other title"}]]
由以下给出:
mediaJSONOptions =
defaultOptions{ sumEncoding = TwoElemArray
, constructorTagModifier = fmap Char.toLower
}
{ key1: value1, key2: value2, ... }
也是有效的。 - Zeta