简体   繁体   English

Aeson:如何使用作为字符串化对象的元素解析对象?

[英]Aeson: how do I parse an object with an element that is a stringified object?

I need to parse an object that has a string element where the string itself is a stringified object: 我需要解析一个具有字符串元素的对象,其中字符串本身是一个字符串化的对象:

{ 
  "a"   : "apples",
  "bar" : "{\"b\":\"bananas\"}"
}

I would like to parse this into Just ( Foo { fooA = "apples", fooBar = Bar { barB = "bananas" } } ) so if parsing of bar returns Nothing then the parsing of the whole object returns Nothing , ie the result is as though the bar element of the object was not stringified. 我想把它解析成Just ( Foo { fooA = "apples", fooBar = Bar { barB = "bananas" } } )所以如果bar的解析返回Nothing那么解析整个对象会返回Nothing ,即结果是好像对象的bar元素没有字符串化。

Here is my attempt in which the parsing of testData returns Nothing : 这是我尝试解析testData返回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

How can I modify the above code to perform closer to what I need? 如何修改上面的代码以更接近我的需要?

You can get more insight into what's going on by using: 您可以通过以下方式更深入地了解正在发生的事情:

main = print (eitherDecode testData :: Either String Foo)

which displays: Left "Error in $: expected Bar, encountered String" 显示: Left "Error in $: expected Bar, encountered String"

In this code: 在这段代码中:

 parseJSON (Object o) = do bar <- (o .: "bar")
                           Foo <$> o .: "a" <*> parseJSON bar

bar is String ... value. barString ... value。

To accomplish what you want to do, you could add a case to the FromJSON instance for Bar to catch this: 要完成您想要执行的操作,您可以向Bar的FromJSON实例添加一个案例来捕获它:

instance FromJSON Bar where
  ...
  parseJSON (String text) =
    case eitherDecode (textToLBS text) of
      Left  e -> fail $ "while decoding a Bar: " ++ e
      Right b -> return b
  ...

Or you could put this code in the parseJSON definition for Foo. 或者您可以将此代码放在Foo的parseJSON定义中。

Here textToLBS converts strict Text to lazy ByteStrings: 这里textToLBS将严格的Text转换为lazy ByteStrings:

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)

Code available at: http://lpaste.net/143183 代码见: http//lpaste.net/143183

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM