Aeson:如何解析具有字符串化对象元素的对象?
Aeson: how do I parse an object with an element that is a stringified object?
我需要解析一个包含字符串元素的对象,其中字符串本身是一个字符串化对象:
{
"a" : "apples",
"bar" : "{\"b\":\"bananas\"}"
}
我想将其解析为 Just ( Foo { fooA = "apples", fooBar = Bar { barB = "bananas" } } )
所以如果解析 bar
returns Nothing
然后解析整个对象 returns Nothing
,即结果好像对象的 bar
元素没有被字符串化。
这是我尝试解析 testData
returns Nothing
:
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Data.Aeson
import Data.Aeson.Types
data Foo = Foo { fooA :: String
, fooBar :: Bar
} deriving (Show)
instance FromJSON Foo where
parseJSON (Object o) = do bar <- (o .: "bar")
Foo <$> o .: "a" <*> parseJSON bar
parseJSON x = typeMismatch "Foo" x
data Bar = Bar { barB :: String
} deriving (Show)
instance FromJSON Bar where
parseJSON (Object o) = Bar <$> o .: "b"
parseJSON x = typeMismatch "Bar" x
testData = "{ \"a\":\"apples\", \"bar\":\"{\\"b\\":\\"bananas\\"}\" }"
main :: IO ()
main = putStrLn $ show d
where d :: Maybe Foo
d = decode testData
如何修改上面的代码以更接近我的需要?
您可以通过以下方式更深入地了解正在发生的事情:
main = print (eitherDecode testData :: Either String Foo)
显示:Left "Error in $: expected Bar, encountered String"
在此代码中:
parseJSON (Object o) = do bar <- (o .: "bar")
Foo <$> o .: "a" <*> parseJSON bar
bar
是 String ...
值。
要完成你想做的事情,你可以向 Bar 的 FromJSON 实例添加一个 case 来捕捉这个:
instance FromJSON Bar where
...
parseJSON (String text) =
case eitherDecode (textToLBS text) of
Left e -> fail $ "while decoding a Bar: " ++ e
Right b -> return b
...
或者您可以将此代码放入 Foo 的 parseJSON 定义中。
此处textToLBS
将严格的文本转换为惰性字节字符串:
import qualified Data.Text as T
import qualified Data.ByteString.Lazy as LBS
import qualified Data.Text.Encoding as TE
textToLBS :: T.Text -> LBS.ByteString
textToLBS t = LBS.fromStrict (TE.encodeUtf8 t)
我需要解析一个包含字符串元素的对象,其中字符串本身是一个字符串化对象:
{
"a" : "apples",
"bar" : "{\"b\":\"bananas\"}"
}
我想将其解析为 Just ( Foo { fooA = "apples", fooBar = Bar { barB = "bananas" } } )
所以如果解析 bar
returns Nothing
然后解析整个对象 returns Nothing
,即结果好像对象的 bar
元素没有被字符串化。
这是我尝试解析 testData
returns Nothing
:
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Data.Aeson
import Data.Aeson.Types
data Foo = Foo { fooA :: String
, fooBar :: Bar
} deriving (Show)
instance FromJSON Foo where
parseJSON (Object o) = do bar <- (o .: "bar")
Foo <$> o .: "a" <*> parseJSON bar
parseJSON x = typeMismatch "Foo" x
data Bar = Bar { barB :: String
} deriving (Show)
instance FromJSON Bar where
parseJSON (Object o) = Bar <$> o .: "b"
parseJSON x = typeMismatch "Bar" x
testData = "{ \"a\":\"apples\", \"bar\":\"{\\"b\\":\\"bananas\\"}\" }"
main :: IO ()
main = putStrLn $ show d
where d :: Maybe Foo
d = decode testData
如何修改上面的代码以更接近我的需要?
您可以通过以下方式更深入地了解正在发生的事情:
main = print (eitherDecode testData :: Either String Foo)
显示:Left "Error in $: expected Bar, encountered String"
在此代码中:
parseJSON (Object o) = do bar <- (o .: "bar")
Foo <$> o .: "a" <*> parseJSON bar
bar
是 String ...
值。
要完成你想做的事情,你可以向 Bar 的 FromJSON 实例添加一个 case 来捕捉这个:
instance FromJSON Bar where
...
parseJSON (String text) =
case eitherDecode (textToLBS text) of
Left e -> fail $ "while decoding a Bar: " ++ e
Right b -> return b
...
或者您可以将此代码放入 Foo 的 parseJSON 定义中。
此处textToLBS
将严格的文本转换为惰性字节字符串:
import qualified Data.Text as T
import qualified Data.ByteString.Lazy as LBS
import qualified Data.Text.Encoding as TE
textToLBS :: T.Text -> LBS.ByteString
textToLBS t = LBS.fromStrict (TE.encodeUtf8 t)