首页 > 解决方案 > Haskell,Aeson:使用部分不必要的值解析嵌套的 JSON

问题描述

我是一个初学者,试图通过解析我在网上找到的一些 json 文件来了解更多关于 Haskell 和 Aeson 的信息。

我有一个.json看起来像这样的

"Abilities": {
    "Prime": {
          "Ammo": 210,
          "Available": true,
          "Diposition": 3,
          "Type": "Secondary",
          "Class": "Pistols",
          "NormalAttack": {
            "Chance": 0.25,
            "Streak": 2,
            "Rate": 2.67,
            "ShotType": "Hit-Scan",
            "Damage": {
              "Front": 15,
              "Back": 15,
              "Up": 120,
              "Down": 40
            },
              "Status": 0.25
            }
          "Accuracy": 9.8,
          "Reload": 3,
          "Name": "Prime",
          "Magazine": 16,
            },
    "Dual": {
          "Name": "Dual",
          "Available": true,
          "Diposition": 4,
          "Class": "Swords",
          "Type": "Melee",
          "NormalAttack": {
            "Chance": 0.25,
            "Streak": 3,
            "Rate": 1.08,
            "Damage": {
              "Down": 35
            },
              "Status": 0.15
      }
    }
}

该文件包含一些我需要的信息,但主要是我不需要的信息。

这是我迄今为止尝试过的

{-# LANGUAGE DeriveGeneric #-}

module Lib
    ( someFunc
    ) where

import           Data.Aeson
import           Data.HashMap.Strict as HS
import           Data.Maybe
import           Data.Text
import           Data.Map.Strict
import           GHC.Generics


location = "src/this.json"

someFunc :: IO ()
someFunc = putStrLn "someFunc"



data Abilities = Abilities { abilities :: Map String Ability } deriving (Generic, Show)

instance FromJSON Abilities where
  parseJSON = withObject "Abilities" $
    \v -> Abilities
    <$> v .: pack "Abilities"


data Ability = Ability { ammo         :: Double
                       , normalAttack :: Effect
                       , accuracy     :: Double
                       , name         :: String
                       , diposition   :: Double
                       , reload       :: Double
                       } deriving (Generic, Show)

instance FromJSON Ability where
  parseJSON = withObject "Ability" $
    \v -> Ability
    <$> v .: pack "Ammo"
    <*> v .: pack "NormalAttack"
    <*> v .: pack "Accuracy"
    <*> v .: pack "Name"
    <*> v .: pack "Diposition"
    <*> v .: pack "Reload"


data Effect = Effect { chance :: Double
                     , streak :: Double
                     , rate   :: Double
                     , damage :: Damage
                     , status :: Double
                     } deriving (Generic, Show)

instance FromJSON Effect where
  parseJSON = withObject "Effect" $
    \v -> Effect
    <$> v .: pack "Chance"
    <*> v .: pack "Streak"
    <*> v .: pack "Rate"
    <*> v .: pack "Damage"
    <*> v .: pack "Status"


data Damage = Damage { front :: Double
                     , back  :: Double
                     , up    :: Double
                     , down  :: Double
                     } deriving (Generic, Show)

instance FromJSON Damage where
  parseJSON = withObject "Damage" $
    \v -> Damage
    <$> v .: pack "Front"
    <*> v .: pack "Back"
    <*> v .: pack "Up"
    <*> v .: pack "Down"


main = do
  x <- eitherDecodeFileStrict location :: IO (Either String Abilities)
  print x

我知道解析信息的几种不同方法

  1. 通过解析文件 has Aeson ValueorAeson Object并申请Data.HashMap.Strict.toList将其转换为[(k, v)]. 麻烦的是,在一个大文件上,这种方法变得非常混乱。

  2. 通过使用unConstructor像这样工作的几个函数

unConstruct (Constructor x) = case (Constructor x) of Constructor x -> x

但同样的问题:它变得非常不可读并且非常混乱。


这就是为什么我要解析.json文件,如上面的代码所示。


但是解析在代码中的某处失败,因为我得到Nothing了输出。

.json文件似乎很好,因为如果我使用

main = do
  x <- decodeFileStrict location :: IO (Maybe Object)
  print x

它工作得很好,使用适当的默认 aeson 数据类型打印文件的内容。


我可能做错了什么?


编辑:实施了@danidiaz 在评论中建议的修复。

错误信息:Left "Error in $.Abilities['someAbility']: key \"Ammo\" not present"

标签: jsonparsinghaskellaeson

解决方案


推荐阅读