Haskell/Aseon:输出JSON作为一个对象
Haskell/Aseon: output JSON as one object
我有以下 Haskell 代码,它在 JSON 中编码数据类型 User
的列表并将其打印到标准输出:
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Data.Aeson
import Data.Text
import qualified Data.ByteString.Lazy.Char8 as B
data User = User
{ id :: String
, name :: String
, address :: String
} deriving (Show)
instance ToJSON User where
toJSON (User id name address) = object
[ pack id .= object
[ "name" .= name
, "address" .= address
]
]
users :: [User]
users = [ User "user 1" "name of user 1" "address of user 1"
, User "user 2" "name of user 2" "address of user 2"
]
main :: IO ()
main = B.putStrLn $ encode users
此时,代码产生以下输出:
[
{
"user 1": {
"address": "address of user 1",
"name": "name of user 1"
}
},
{
"user 2": {
"address": "address of user 2",
"name": "name of user 2"
}
}
]
但是,我想输出以下JSON结构(加入内部两个对象):
{
"user 1": {
"name": "name of user 1",
"address": "address of user 1"
},
"user 2": {
"name": "name of user 2",
"address": "address of user 2"
}
}
我如何更改 toJSON
才能打印所需的编码 JSON?
How will I have to change toJSON in order to print the desired encoded JSON?
您无法为 User
更改 toJSON
以打印所需的编码 JSON。问题不在 User
编码中,而在列表编码中。简单列表只是编码为 JSON 数组。 JSON 数组没有值(所以你不能有 ["user 1":{...}]
,因此每个对象都被包装到 {}
中)。这个问题可以用不同的方式解决。最简单的解决方案之一是为 User
列表编写自定义编码器。这是它的样子:
import qualified Data.HashMap.Strict as HM
usersEncode :: [User] -> Object
usersEncode = HM.unions . map (\(Object user) -> user) . map toJSON
然后在 main
你可以这样称呼它:
main = B.putStrLn $ encode $ usersEncode users
它会为您提供所需的输出。
诀窍在于 aeson
将对象存储为 HashMap
从 Text
到 Value
。 HashMap
被编码为 JSON 对象。因此,给定解决方案的想法是将每个用户转换为单例 HashMap
,然后联合所有 HashMap
。
注意:它会从列表中删除重复userId
的用户。
我有以下 Haskell 代码,它在 JSON 中编码数据类型 User
的列表并将其打印到标准输出:
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Data.Aeson
import Data.Text
import qualified Data.ByteString.Lazy.Char8 as B
data User = User
{ id :: String
, name :: String
, address :: String
} deriving (Show)
instance ToJSON User where
toJSON (User id name address) = object
[ pack id .= object
[ "name" .= name
, "address" .= address
]
]
users :: [User]
users = [ User "user 1" "name of user 1" "address of user 1"
, User "user 2" "name of user 2" "address of user 2"
]
main :: IO ()
main = B.putStrLn $ encode users
此时,代码产生以下输出:
[
{
"user 1": {
"address": "address of user 1",
"name": "name of user 1"
}
},
{
"user 2": {
"address": "address of user 2",
"name": "name of user 2"
}
}
]
但是,我想输出以下JSON结构(加入内部两个对象):
{
"user 1": {
"name": "name of user 1",
"address": "address of user 1"
},
"user 2": {
"name": "name of user 2",
"address": "address of user 2"
}
}
我如何更改 toJSON
才能打印所需的编码 JSON?
How will I have to change toJSON in order to print the desired encoded JSON?
您无法为 User
更改 toJSON
以打印所需的编码 JSON。问题不在 User
编码中,而在列表编码中。简单列表只是编码为 JSON 数组。 JSON 数组没有值(所以你不能有 ["user 1":{...}]
,因此每个对象都被包装到 {}
中)。这个问题可以用不同的方式解决。最简单的解决方案之一是为 User
列表编写自定义编码器。这是它的样子:
import qualified Data.HashMap.Strict as HM
usersEncode :: [User] -> Object
usersEncode = HM.unions . map (\(Object user) -> user) . map toJSON
然后在 main
你可以这样称呼它:
main = B.putStrLn $ encode $ usersEncode users
它会为您提供所需的输出。
诀窍在于 aeson
将对象存储为 HashMap
从 Text
到 Value
。 HashMap
被编码为 JSON 对象。因此,给定解决方案的想法是将每个用户转换为单例 HashMap
,然后联合所有 HashMap
。
注意:它会从列表中删除重复userId
的用户。