Произвольные ключи JSON с Aeson - Haskell

У меня есть куча вложенных объектов JSON с произвольными ключами.

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

        }
    }

}

Куда , ,ABC неизвестны раньше времени. У каждого из этих троих тоже могут быть братья и сестры.

Интересно, есть ли способ разобрать это в пользовательский тип с Aeson каким-то элегантным способом? То, что я делал, загружает это в Эзона.Object

Как бы вы пошли о реализацииFromJSON для этого вида объекта JSON?

Спасибо!

Редактировать:

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

Это должно компилироваться вCountryDatabase где...

type City            = Map String String
type Country         = Map String City
type CountryDatabase = Map String Country 
 Honza Pokorny24 июн. 2013 г., 19:36
Вопрос дополнен более конкретным примером структур данных.
 Mike Craig24 июн. 2013 г., 19:25
Можете ли вы привести пример пользовательского типа, который выхотел бы разобраться? Я думаю, что это прояснит вопрос.
 Matvey Aksenov24 июн. 2013 г., 18:01
Это'не очень понятнокак Вы хотели бы проанализировать этот JSON. У него всегда есть только 3 вложенных ключа и строка?

Ответы на вопрос(1)

Решение Вопроса

Вы можете использовать повторноFromJSON экземплярMap String v, Что-то вроде следующего:

{-# 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 <
{-# 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)
gt; parseJSON val newtype Country = Country (Map String City) deriving Show instance FromJSON Country where parseJSON val = Country <
{-# 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)
gt; parseJSON val newtype DB = DB (Map String Country) deriving Show instance FromJSON DB where parseJSON val = DB <
{-# 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)
gt; parseJSON val main :: IO () main = do file <- head <
{-# 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)
gt; getArgs str <- LBS.readFile file print (decode str :: Maybe DB)

Выход:

[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: вы можете сделать это безnewtypeЯ использовал их только для ясности.

 davidchambers04 июл. 2015 г., 00:36
Этот ответ очень полезен! Может ли это быть изменено, чтобы игнорировать нестроковые значения? (Замена"1111" с1111например, вызывает сбой синтаксического анализа.)
 AdHominem31 мая 2017 г., 12:23
Как будет выглядеть экземпляр ToJSON для этого?

Ваш ответ на вопрос