Aeson 使用之前解析的默认值解析 JSON
Aeson parse JSON with default value from previous parse
我想解析以下内容json:
{
"defaults": {
"align": "left"
},
"animals": [
{
"kind": "cat",
"name": "Oscar",
"align": "center"
},
{
"kind": "dog",
"name": "Max"
}
]
}
解析对齐:
data Align = Left | Center | Right
instance FromJSON Align where
parseJSON (String "left") = pure Left
parseJSON (String "center") = pure Center
parseJSON (String "right") = pure Right
parseJSON _ = fail "Expect one of [left, center, right]."
解析默认值:
data BlockDefaults = BlockDefaults { align :: Align }
-- default value Center if key does not exist
blockDefaults :: BlockDefaults
blockDefaults = BlockDefaults { align = Center }
instance FromJSON BlockDefaults where
parseJSON = withObject "defaults" $ \o -> BlockDefaults <$> o .:? "align" .!= align blockDefaults
现在我想解析狗和猫。
如果 align
不存在(如 dog
),它应该从默认值(left
)中获取值。
所以 dog
应该变成 Dog{name="Max", align=Center}
和 cat
Cat{name="Oscar", align=Left}
.
但是如何访问 parseJSON
中的默认对齐值?
-- pseudo parse code
instance FromJSON Animal where
parseJSON = withObject "animal" $ \o ->
Animal <$>
o .: "kind" <*>
o .: "name" <*>
o .:? "align" .!= <DefaultValue> -- How to access value from defaults object?
我不想再次解析每只动物的默认值,那么如何访问之前解析过的那些默认值?
假设 defaults
和其他 animals
.
中有更多的值
所以动物解析器代码现在看起来像这样:
parseAnimal :: BlockDefaults -> Value -> Parser Animal
parseAnimal defaults = withObject "animal" $ \o ->
Animal <$>
o .: "kind" <*>
o .: "name" <*>
(
BlockDefaults <$>
o .:? "align" .!= align defaults
)
您不必使用 FromJSON
class,尤其是在解析可能依赖于 运行 时间数据的情况下。通过声明自己的解析器的自由,您可以轻松定义
parseAnimal :: BlockDefaults -> Value -> Parser Animal
或者,您可以将 Animal
概括为一种可以在不知道默认值的情况下进行解析的形式,例如,只需输入 Maybe
即可。例如:
data Animal_ a
= Animal
Kind
Name
a
type Animal = Animal_ Align
parseAnimal :: Value -> Parser (Animal_ (Maybe Align))
animalWithDefault :: BlockDefaults -> Animal_ (Maybe Align) -> Animal
我的评论建议是使用 BlockDefaults -> Animal
作为实例。例如:
#!/usr/bin/env cabal
{- cabal:
build-depends: base, aeson
-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE FlexibleInstances #-}
import Prelude hiding (Either(..)) -- This is why you don't name your constructors 'Left' and 'Right'
import Data.Aeson
data Align = Left | Center | Right
deriving (Show)
instance FromJSON Align where
parseJSON (String "left") = pure Left
parseJSON (String "center") = pure Center
parseJSON (String "right") = pure Right
parseJSON _ = fail "Expect one of [left, center, right]."
data BlockDefaults = BlockDefaults { align :: Align }
-- default value Center if key does not exist
blockDefaults :: BlockDefaults
blockDefaults = BlockDefaults { align = Center }
instance FromJSON BlockDefaults where
parseJSON = withObject "defaults" $ \o -> BlockDefaults <$> o .:? "align" .!= align blockDefaults
data Animal = Animal { kind :: String
, name :: String
, aalign :: Align
}
deriving (Show)
instance FromJSON (BlockDefaults -> Animal) where
parseJSON = withObject "Animal" $ \o ->
do k <- o .: "kind"
n <- o .: "name"
a <- o .:? "align"
pure $ \def -> Animal k n (maybe (align def) id a)
main :: IO ()
main = print (decode "{ \"kind\": \"k\", \"name\" : \"n\" }" <*> Just blockDefaults :: Maybe Animal)
我想解析以下内容json:
{
"defaults": {
"align": "left"
},
"animals": [
{
"kind": "cat",
"name": "Oscar",
"align": "center"
},
{
"kind": "dog",
"name": "Max"
}
]
}
解析对齐:
data Align = Left | Center | Right
instance FromJSON Align where
parseJSON (String "left") = pure Left
parseJSON (String "center") = pure Center
parseJSON (String "right") = pure Right
parseJSON _ = fail "Expect one of [left, center, right]."
解析默认值:
data BlockDefaults = BlockDefaults { align :: Align }
-- default value Center if key does not exist
blockDefaults :: BlockDefaults
blockDefaults = BlockDefaults { align = Center }
instance FromJSON BlockDefaults where
parseJSON = withObject "defaults" $ \o -> BlockDefaults <$> o .:? "align" .!= align blockDefaults
现在我想解析狗和猫。
如果 align
不存在(如 dog
),它应该从默认值(left
)中获取值。
所以 dog
应该变成 Dog{name="Max", align=Center}
和 cat
Cat{name="Oscar", align=Left}
.
但是如何访问 parseJSON
中的默认对齐值?
-- pseudo parse code
instance FromJSON Animal where
parseJSON = withObject "animal" $ \o ->
Animal <$>
o .: "kind" <*>
o .: "name" <*>
o .:? "align" .!= <DefaultValue> -- How to access value from defaults object?
我不想再次解析每只动物的默认值,那么如何访问之前解析过的那些默认值?
假设 defaults
和其他 animals
.
所以动物解析器代码现在看起来像这样:
parseAnimal :: BlockDefaults -> Value -> Parser Animal
parseAnimal defaults = withObject "animal" $ \o ->
Animal <$>
o .: "kind" <*>
o .: "name" <*>
(
BlockDefaults <$>
o .:? "align" .!= align defaults
)
您不必使用 FromJSON
class,尤其是在解析可能依赖于 运行 时间数据的情况下。通过声明自己的解析器的自由,您可以轻松定义
parseAnimal :: BlockDefaults -> Value -> Parser Animal
或者,您可以将 Animal
概括为一种可以在不知道默认值的情况下进行解析的形式,例如,只需输入 Maybe
即可。例如:
data Animal_ a
= Animal
Kind
Name
a
type Animal = Animal_ Align
parseAnimal :: Value -> Parser (Animal_ (Maybe Align))
animalWithDefault :: BlockDefaults -> Animal_ (Maybe Align) -> Animal
我的评论建议是使用 BlockDefaults -> Animal
作为实例。例如:
#!/usr/bin/env cabal
{- cabal:
build-depends: base, aeson
-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE FlexibleInstances #-}
import Prelude hiding (Either(..)) -- This is why you don't name your constructors 'Left' and 'Right'
import Data.Aeson
data Align = Left | Center | Right
deriving (Show)
instance FromJSON Align where
parseJSON (String "left") = pure Left
parseJSON (String "center") = pure Center
parseJSON (String "right") = pure Right
parseJSON _ = fail "Expect one of [left, center, right]."
data BlockDefaults = BlockDefaults { align :: Align }
-- default value Center if key does not exist
blockDefaults :: BlockDefaults
blockDefaults = BlockDefaults { align = Center }
instance FromJSON BlockDefaults where
parseJSON = withObject "defaults" $ \o -> BlockDefaults <$> o .:? "align" .!= align blockDefaults
data Animal = Animal { kind :: String
, name :: String
, aalign :: Align
}
deriving (Show)
instance FromJSON (BlockDefaults -> Animal) where
parseJSON = withObject "Animal" $ \o ->
do k <- o .: "kind"
n <- o .: "name"
a <- o .:? "align"
pure $ \def -> Animal k n (maybe (align def) id a)
main :: IO ()
main = print (decode "{ \"kind\": \"k\", \"name\" : \"n\" }" <*> Just blockDefaults :: Maybe Animal)