Aeson使用先前解析的默认值解析JSON

问题描述 投票:1回答:1

我想解析以下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
    )
json haskell aeson
1个回答
2
投票

您不必使用FromJSON类,尤其是在其中解析可能取决于运行时数据的情况下。可以自由声明自己的解析器,然后可以轻松定义

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
© www.soinside.com 2019 - 2024. All rights reserved.