【问题标题】:Using Aeson generics to construct JSON with a value as key holding another value使用 Aeson 泛型构造 JSON,以一个值作为键来保存另一个值
【发布时间】:2014-01-26 01:37:12
【问题描述】:

在尝试使用 Aeson JSON 库的同时尝试使用 github gist API。我在生成的 ToJSON 实例时遇到了问题,我不知道具体如何解决。

我需要在里面包含一个值,并且与该值关联的键也需要是一个值,而不是预定义的键名。它更容易显示。期望的输出是,

{
    "public": true, 
    "description": "Something..", 
    "files": {"This Thing.md": {"content": "Here we go!"}}
}

文件名的值在哪里保存内容,但目前我得到了,

{
    "public": true, 
    "description": "Something..", 
    "files": {"filename": "This Thing.md", "content": "Here we go!"}
}

这不是我真正需要的。当前的代码是,

{-# LANGUAGE OverloadedStrings, DeriveGeneric #-}
import Data.Text (Text)
import Data.Aeson
import GHC.Generics

data GistContent = GistContent
    { filename :: Text
    , content :: Text
      } deriving (Show, Generic)

instance ToJSON GistContent

data Gist = Gist
    { description :: Text
    , public      :: Bool
    , files       :: GistContent
      } deriving (Show, Generic)

instance ToJSON Gist

假设有可能,我的数据结构需要如何查看才能获得所需的输出?.. 如果使用泛型无法做到这一点,我是如何使用 ToJSON 实例解决的(我可以'也不太清楚那里的结构)?

【问题讨论】:

    标签: haskell aeson


    【解决方案1】:

    您的问题源于不正确的架构。 files 目前只能包含一个GistContent,这是不必要的限制。相反,你会想要一个GistContents 的列表:

    data Gist = Gist
        { description :: Text
        , public      :: Bool
        , files       :: [GistContent]
        } deriving (Show, Generic)
    

    现在考虑对Gist 的另一个约束:每个GistContent 必须有一个不同的filename。强制执行此操作的数据结构是Data.HashMap.Strict.HashMap。从GistContent 中取出filename 并使用文件名作为键:

    data GistContent = GistContent
        { content :: Text
        } deriving (Show, Generic)
    
    data Gist = Gist
        { description :: Text
        , public      :: Bool
        , files       :: HashMap Text GistContent
        } deriving (Show, Generic)
    

    一切顺利。

    【讨论】:

    • 甜,成功了 :) 不知道为什么我从来没有想到过 HashMap,Aeson 还是有点陌生​​,但我希望很快就能克服这个障碍。跨度>
    • 查看HashMap 实例(github.com/bos/aeson/blob/master/Data/Aeson/Types/…)的来源可能会有所启发 - HashMap 实际上用作 Aeson 对象(github.com/bos/aeson/blob/master/Data/Aeson/Types/…)中的内部结构,这使得它特别简洁。
    • @icktoofay - 你是说上面的Data.HashMap.*Strict*.HashMap 吗?
    • @Ganesh:我做到了,尽管两者似乎都有效。不错的收获。
    【解决方案2】:

    这是手动编写的实例(参见documentation for the class):

    instance ToJSON GistContent where
       toJSON (GistContent { filename = f, content = c }) = object [f .= c]
    

    我怀疑是否有任何方法可以使用您现有的数据类型和自动生成的实例来实现这一点,因为他们所能做的就是使用标准方案遵循数据类型。请注意,您仍然可以使用Gist 的通用实例,因为这将调用GistContent 的(非通用)实例。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-08
      相关资源
      最近更新 更多