Haskell - 使用aeson生成JSON会给出不正确的字段顺序

时间:2016-06-16 17:07:32

标签: json haskell aeson

我正在尝试将数据类型编码为JSON:

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}

import Data.Aeson

data Trend = Trend
            { period :: String
            , africa :: String
            , americas :: String
            , asia :: String
            } deriving Show

instance ToJSON Trend where
  toJSON Trend{..} = 
    object [ "Period"    .= period
           , "Africa"    .= africa
           , "Americas"  .= americas
           , "Asia"      .= asia
           ]

test = Trend {period = "2013", africa = "1", americas = "2", asia = "3"}

给出了:

λ: encode test
λ: "{\"Asia\":\"3\",\"Period\":\"2013\",\"Africa\":\"1\",\"Americas\":\"2\"}"

我不明白为什么生成的JSON没有与我的数据类型相同的字段。

我期待输出为{期间,非洲,美洲,亚洲},我正在获得{亚洲,期间,非洲,美洲)

据我所知,在传递信息时,订单并不重要,但我很好奇为何会发生这种情况。

2 个答案:

答案 0 :(得分:5)

您可以使用自toEncoding以来可用的aeson-0.10方法(尽管可能,但请使用aeson-0.11)。在这种情况下,您可以更好地控制生成的结构:

instance ToJSON Trend where
  toJSON Trend{..} = 
    object [ "Period"    .= period
           , "Africa"    .= africa
           , "Americas"  .= americas
           , "Asia"      .= asia
           ]

  toEncoding Trend {..} =
    pairs $ "Period"   .= period
         <> "Africa"   .= africa
         <> "Americas" .= americas
         <> "Asia"     .= asia 

或者,如果这很简单,则值得使用Generic派生

instance ToJSON Trend where
    toJSON = genericToJSON defaultOptions { fieldLabelModifier = capitaliseFirst }
      where
        capitaliseFirst (x:xs) = toUpper x : xs
        capitaliseFirst []     = []

答案 1 :(得分:3)

它发生的原因是因为Aeson对象只是一个HashMap,当aeson将HashMap转换为文本时,它只是按照HashMap返回它们的顺序序列化键值对 - 这可能与HashMap无关。插入密钥的顺序。