2016-06-16 8 views
3

ich einen Datentyp in JSON zu kodieren versuchen:Haskell - mit Aeson JSON Generierung gibt eine falsche Reihenfolge der Felder

{-# 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"} 

Welche gibt:

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

Ich verstehe nicht, warum die erzeugte JSON enthält die Felder nicht in der gleichen Reihenfolge wie mein Datentyp.

Ich erwarte die Ausgabe zu sein {period, Afrika, Nord- und Südamerika, Asien} und ich bin immer {Asien, Zeit, Afrika, Nord- und Südamerika)

Ich verstehe, dass Informationen über nebenbei, die Reihenfolge ist nicht wichtig aber ich bin neugierig, warum das passiert.

+7

JSON hat keine ‚richtigen‘ Reihenfolge der Felder verwendet wird. edit: siehe die Antwort [hier] (http://stackoverflow.com/questions/3948206/json-order-mixed-up) – pdexter

Antwort

4

Sie können toEncoding Methode verwenden, die seit aeson-0.10 verfügbar ist (verwenden Sie aeson-0.11 obwohl, wenn nur möglich). In diesem Fall haben Sie mehr Kontrolle über die Struktur erzeugt:

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 

oder im Falle so einfach ist das, lohnt Generic Ableitung

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

Danke, aber ich bin ein bisschen verwirrt. Soll ich etwas in die Zeile "Code hier eingeben" einfügen? – matthias

+0

Ah, das war etwas, das von inlne editor eingeführt wurde: S – phadej

+0

muss ich ein bestimmtes Pragma laden, um 'toEncoding' zu verwenden? Ich bekomme eine "Serie" nicht im Umfang und ist '<>' spezifisch für AESON? – matthias

3

Der Grund dafür ist, dass ein Aeson-Objekt nur eine HashMap ist und wenn Aeson die HashMap in Text konvertiert, serialisiert es die Schlüssel/Wert-Paare in der Reihenfolge, in der die HashMap sie zurückgibt die Reihenfolge, in der die Schlüssel eingefügt wurden.