Haskell/Aseon: вывод JSON как одного объекта
У меня есть следующий код Haskell, который кодирует список типов данных User
в JSON и выводит его на стандартный вывод:
{-# 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?
1 ответ
Как я должен буду изменить toJSON, чтобы напечатать желаемый закодированный JSON?
Вы ничего не можете сделать, чтобы изменить toJSON
за User
распечатать желаемый закодированный 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
s.
Примечание: это удалит пользователей с дублированием userId
из списка.