我想解析和编写JSON对象,这些对象具有一些共同的基本属性和一些附加的单独属性。例如,假设我们有两种类型的对象User
和Email
。这两种类型共享相同的基本属性foo
和bar
,但它们具有特定于其类型的附加属性:
User:
{"foo": "foo", "bar": "bar", "user": "me", "age": "42"}
Email:
{"foo": "foo", "bar": "bar", "email": "me@example.com"}
我已经为单独的对象User
、Email
和Base
编写了FromJSON
和ToJSON
示例,现在我的想法是定义一个 Package 器对象,将Base
和任何其他类型的FromJSON
和ToJSON
示例组合在一起。
data Wrapper a = Wrapper Base a
instance FromJSON a => FromJSON (Wrapper a) where
parseJSON = withObject "Wrapper" $ \v -> Wrapper <$> parseJSON (Object v) <*> parseJSON (Object v)
instance ToJSON a => ToJSON (Wrapper a) where
toJSON (Wrapper base a) = Object (toObject "base" (toJSON base) <> toObject "custom" (toJSON a))
where
toObject :: Text -> Value -> KeyMap Value
toObject _ (Object v) = v
toObject key v = KeyMap.singleton (Key.fromText key) v
toEncoding = genericToEncoding defaultOptions
FromJSON
实现看起来工作得很好,而且toJSON
函数似乎将所有属性打包到一个对象中,不幸的是,我找不到将两个Encoding
合并在一起的解决方案。默认的toEncoding
实现将基本属性和自定义属性打包到两个单独的JSON对象中,并将底层Builder
与unsafeToEncoding
合并也无济于事。
是否有任何aeson
功能我完全错过或有一个更简单的方法来解决我的问题?任何帮助都是感激不尽的。谢谢!
更新
多亏了丹尼尔瓦格纳的回答,我定义了一个新的类型类ToObject
,并使Wrapper数据类型更通用一些。
newtype Merged a b = Merged (a, b)
deriving stock (Show, Generic)
deriving newtype (Eq)
class ToObject a where
toObject :: a -> Object
toSeries :: a -> Series
instance (ToObject a, ToObject b) => ToObject (Merged a b) where
toObject (Merged (a, b)) = toObject a <> toObject b
toSeries (Merged (a, b)) = toSeries a <> toSeries b
instance (FromJSON a, FromJSON b) => FromJSON (Merged a b) where
parseJSON = Json.withObject "Merged" $ \v -> fmap Merged ((,) <$> parseJSON (Object v) <*> parseJSON (Object v))
instance (ToObject a, ToObject b) => ToJSON (Merged a b) where
toJSON = Object . toObject
toEncoding = Json.pairs . toSeries
1条答案
按热度按时间rxztt3cl1#
您可以使用
pairs
和pair
构建所需的内容。