【问题标题】:How can I parse an Aeson Object into my own custom type?如何将 Aeson 对象解析为我自己的自定义类型?
【发布时间】:2020-07-19 21:08:21
【问题描述】:

我正在尝试使用 Aeson 编写 JSON 解析器。

The JSON I'm working with

我在代码中调用 JSON 的方式:

testReq :: Request
testReq = parseRequest_ "https://api.openweathermap.org/data/2.5/onecall?lat=41.63526&lon=-70.92701&exclude=minutely&appid=93120a85abf28f8fb1cdae14ffd7435d&units=metric"

首先我定义我的自定义类型

type Celsius       = Double
type HPA           = Int --Hectopascal Pressure Unit
type Percent       = Int
type Meter         = Int
type MeterPerSec   = Double
type CompassDegree = Int

data WeatherObj =
  WeatherObj
    { time :: UTCTime
    , temp :: Celsius
    , feels_like :: Celsius
    , pressure :: HPA
    , humidity :: Percent
    , visibility :: Meter
    , wind_speed :: MeterPerSec
    , wind_deg :: CompassDegree
    }
  deriving (Eq, Show, Generic)

接下来我编写我的 FromJSON 实例,我知道它有效,因为如果我运行 parseCurrentWeather testReq 我会返回 WeatherObj {time = 2020-07-19 16:54:43 UTC, temp = 25.51, feels_like = 29.49, pressure = 1012, humidity = 83, visibility = 10000, wind_speed = 1.34, wind_deg = 247} 这是完美的!

instance FromJSON WeatherObj where
  parseJSON = withObject "weatherObj" $ \obj -> do
    timeOffset  <- obj .: "timezone_offset"
    currentO    <- obj .: "current"
    dt          <- currentO .: "dt"
    temp        <- currentO .: "temp"
    feels_like  <- currentO .: "feels_like"
    pressure    <- currentO .: "pressure"
    humidity    <- currentO .: "humidity"
    visibility  <- currentO .: "visibility"
    wind_speed  <- currentO .: "wind_speed"
    wind_deg    <- currentO .: "wind_deg"
    pure $ WeatherObj (makeLocalTime dt timeOffset)
                       temp feels_like
                       pressure humidity
                       visibility wind_speed
                       wind_deg

parseCurrentWeather :: Request -> IO WeatherObj
parseCurrentWeather req = do
  current <- fetchCurrentWeather req
  pure $ getResponseBody current

现在我需要弄清楚如何解析每小时的天气,这应该会给我 48 个对象。这段代码就像我运行parseHourly testReq 时一样工作,我得到一长串JSON,没有例外。此 JSON 肯定与链接中的 JSON 匹配。到目前为止,我看起来很棒。

fetchHourly :: Request -> IO (Response HourlyWeathers) --Could also be IO (Response Object)
fetchHourly = httpJSON 

data HourlyWeathers =
  HourlyWeathers
    { getHours :: [Object] }
    deriving (Eq, Show, Generic)

instance FromJSON HourlyWeathers where
  parseJSON = withObject "hourlyWeather" $ \obj -> do
    allHours  <- obj .: "hourly"
    pure $ HourlyWeathers allHours
           
parseHourly :: Request -> IO HourlyWeathers
parseHourly req = do
  hours <- fetchHourly req
  pure $ getResponseBody hours

现在我们遇到了有问题的代码。我想将objToWeatherObj 映射到我使用parseHourly 生成的对象列表中。我似乎无法克服的问题是,当我运行 parseHourlyObjects 时,我会返回一个所有空的列表。

parseHourlyObjects :: Request -> IO [Maybe WeatherObj]
parseHourlyObjects req = do 
  hourly <- fetchHourly req
  let x = getHours $ getResponseBody hourly
      y = fmap objToWeatherObj x 
  pure y

objToWeatherObj :: Object -> Maybe WeatherObj
objToWeatherObj = (decode . encode)

我已经能够为WeatherObj 编写一个ToJSON 实例,但结果证明这无关紧要,因为我需要将通用Object 解析为WeatherObj。我相信我这里需要的函数是decode,虽然我可能是错的。

【问题讨论】:

    标签: haskell aeson


    【解决方案1】:

    给定:

    data WeatherObj =
      WeatherObj
        { time :: UTCTime
        , temp :: Celsius
        , feels_like :: Celsius
        , pressure :: HPA
        , humidity :: Percent
        , visibility :: Meter
        , wind_speed :: MeterPerSec
        , wind_deg :: CompassDegree
        }
      deriving (Eq, Show, Generic, FromJSON)
    

    请注意,它现在也派生 FromJSON

    你可以:

    decode "{\"time\":\"...\",...}" :: Maybe WeatherObj
    

    并获得一个Maybe WeatherObj。通过编写您自己的 FromJSON 实例,我认为您可能使您的生活变得比需要的更具挑战性。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-04
      • 1970-01-01
      • 1970-01-01
      • 2021-02-14
      • 2018-02-26
      • 1970-01-01
      相关资源
      最近更新 更多