haskell 当第一个关键字是变量时,使用aeson解析json

slsn1g29  于 2022-11-14  发布在  其他
关注(0)|答案(3)|浏览(147)

我的json看起来像这样

{
    "NW011": {
        "version": 1.0,
        "compatiblehardware": ["N21"],
        "description": "TWIN"
   }
}

问题是键NW011是变量。当我开始解析的时候我知道这个键,但是我不知道如何为aeson声明数据类型和示例。

cbeh67ev

cbeh67ev1#

首先,需要声明一个数据类型来模拟数据的实际情况。我假设“NW011”实际上是一种字段,尽管所讨论的JSON格式已经将其提升为一个记录名。因此:

data Thing = Thing {
   thingName :: Text,  -- E.g. "NW011"
   thingVersion :: Text, -- I'm assuming that "Version" could include "1.2.3A" and hence should be a string, not a number.
   thingCompatible :: [Text],
   thingDescription :: Text
}

现在是示例。通常当你解析JSON时,你会有一个带有固定字段名的对象,所以你可以使用“.:“来提取它们。在这种情况下,你的最外层结构是一个单字段对象,其中的字段名为“NW011”,包含一个更传统的对象。
所以你需要写一个示例来检索这个原始对象。我假设你可能有几个这样的对象,它们有不同的名字,比如“NW012”等等,所以实际上你的外部结构是这些东西的一个列表。如果你解析你给出的例子,你会得到一个单元素列表。
在Aeson中,“Object”是一个查找表的 Package 器(即一个HashMap),所以你需要做的就是遍历HashMap,通过名称提取对象,所以答案应该看起来像这样(尽管我还没有尝试编译它):

import qualified Data.HashMap.Strict as H

instance FromJSON [Thing] where
   parseJSON (Object v) = mapM parseItem $ H.toList v
      -- 'v' is a HashMap containing a key "NW011".
   where
      parseItem (k, Object v2) = 
         -- "v2" is a HashMap containing keys for the fixed field names ("version" etc.)
         Thing k <$> 
         v2 .: "version" <*>
         v2 .: "compatiblehardware" <*>
         v2 .: "description"

注意,这里只给出了成功的例子,你的代码还应该包括parseJSON和parseItem的参数不是对象的例子。

t9aqgxwy

t9aqgxwy2#

Aeson中的JSON对象只是散列Map。如果需要,可以提取所有键。在这种情况下,不能使用以JSON键命名的字段作为数据类型,因为这不一致,但仍然可以解析和使用JSON。下面是未经测试的代码。

import Data.Aeson
import Data.Text (Text)
import Data.HashMap.Strict as HMap

parseMyJSON :: Value -> Parser (Text,Value)
parseMyJSON (Object v) =
     case HMap.toList v of
        [(k,v)] -> (k, v)
        _       -> fail "More than one key - who sent this thing?"
parseMyJSON _ = fail "Incorrect JSON - expected an object."
dm7nw8vv

dm7nw8vv3#

您可以将JSON解析为(Map Text Thing),其中Thing是您的记录类型。测试代码如下:

{-# LANGUAGE DeriveGeneric #-}

import Data.ByteString.Lazy as BSL
import Data.Text (Text)
import Data.Aeson 
import Data.Map (Map)
import GHC.Generics

-- Record representing a single thing
data Thing =
    Thing { 
        version             :: Float,
        compatiblehardware  :: [Text],
        description         :: Text
    } deriving (Show, Generic)

instance FromJSON Thing

main :: IO()
main = do
    inh <- BSL.readFile "json.txt" 
    case decode inh :: Maybe (Map Text Thing) of
        Just parsed -> print parsed
        Nothing -> print "Unparsable"

下面是测试数据“json.txt”:

{
   "NW011": {
        "version": 1.0,
        "compatiblehardware": ["N21"],
        "description": "TWIN"
   },
   "NW012": {
        "version": 2.4,
        "compatiblehardware": ["N21", "N22"],
        "description": "TURBO"
   }
}

相关问题