2013-06-24 14 views
11

Mam wiele zagnieżdżonych obiektów JSON z dowolnymi kluczami.Arbitralne klucze JSON z Aesonem - Haskell

{ 
    "A": { 
     "B": { 
      "C": "hello" 

     } 
    } 

} 

Gdzie A, B, C nie są znane z wyprzedzeniem. Każdy z tych trzech może mieć także rodzeństwo.

Zastanawiam się, czy istnieje sposób na sparsowanie tego w niestandardowy typ z Aeson w eleganckim sposobem. To, co robiłem, to ładowanie go do Aesona Object.

Jak byś poszła na temat implementacji FromJSON dla tego rodzaju obiektu JSON ?

Dzięki!

Edit:

{ 
    "USA": { 
     "California": { 
      "San Francisco": "Some text" 
     } 
    }, 
    "Canada": { 
     ... 
    } 
} 

ten powinien skompilować do CountryDatabase Gdzie ...

type City   = Map String String 
type Country   = Map String City 
type CountryDatabase = Map String Country 
+1

To nie jest do końca jasne * jak * chciałbyś przetworzyć ten JSON. Czy zawsze ma tylko 3 klucze zagnieżdżone, a następnie ciąg? –

+0

Czy możesz podać przykład niestandardowego typu, który chcesz przeanalizować? Myślę, że to wyjaśniłoby to pytanie. –

+0

Pytanie zaktualizowane o bardziej konkretny przykład struktur danych. –

Odpowiedz

18

można ponownie wykorzystać FromJSON wystąpienie Map String v. Coś jak następny:

{-# LANGUAGE OverloadedStrings #-} 

import Data.Functor 
import Data.Monoid 
import Data.Aeson 
import Data.Map (Map) 
import qualified Data.ByteString.Lazy as LBS 
import System.Environment 

newtype City = City (Map String String) 
    deriving Show 

instance FromJSON City where 
    parseJSON val = City <$> parseJSON val 

newtype Country = Country (Map String City) 
    deriving Show 

instance FromJSON Country where 
    parseJSON val = Country <$> parseJSON val 

newtype DB = DB (Map String Country) 
    deriving Show 

instance FromJSON DB where 
    parseJSON val = DB <$> parseJSON val 

main :: IO() 
main = do 
    file <- head <$> getArgs 
    str <- LBS.readFile file 
    print (decode str :: Maybe DB) 

Wyjście:

[email protected]:/tmp/shum$ cat in.js 
{ 
    "A": { 
     "A1": { 
      "A11": "1111", 
      "A22": "2222" 
     } 
    }, 
    "B": { 
    } 
} 
[email protected]:/tmp/shum$ runhaskell test.hs in.js 
Just (DB (fromList [("A",Country (fromList [("A1",City (fromList [("A11","1111"),("A22","2222")]))])),("B",Country (fromList []))])) 
[email protected]:/tmp/shum$ 

PS: Można to zrobić bez newtype s, użyłem ich tylko dla jasności.

+0

Ta odpowiedź jest bardzo pomocna! Czy można to zmodyfikować, aby ignorować wartości inne niż łańcuchowe? (Na przykład "Zamień" 1111 "' na '1111' powoduje niepowodzenie parsowania.) – davidchambers

+0

Jak wyglądałaby instancja ToJSON? – AdHominem

Powiązane problemy