2013-06-24 27 views
11

Tôi có một loạt các đối tượng JSON lồng nhau với các khóa tùy ý.Các khóa JSON tùy ý với Aeson - Haskell

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

     } 
    } 

} 

đâu A, B, C chưa được biết trước thời hạn. Mỗi người trong số họ cũng có thể có anh chị em ruột.

Tôi tự hỏi liệu có cách nào phân tích cú pháp này thành loại tùy chỉnh với Aeson theo số một số cách thanh lịch hay không. Những gì tôi đã làm là tải nó vào một Aeson Object.

Bạn sẽ làm thế nào để triển khai FromJSON đối với loại đối tượng JSON này?

Cảm ơn!

Sửa:

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

này nên biên dịch để CountryDatabase nơi ...

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

Nó không thực sự rõ ràng * cách * bạn muốn phân tích cú pháp JSON này. Liệu nó luôn luôn chỉ có 3 phím lồng nhau và sau đó là chuỗi? –

+0

Bạn có thể đưa ra ví dụ về loại tùy chỉnh bạn muốn phân tích cú pháp không? Tôi nghĩ rằng sẽ làm rõ câu hỏi. –

+0

Câu hỏi được cập nhật với một ví dụ cụ thể hơn về cấu trúc dữ liệu. –

Trả lời

18

Bạn có thể tái sử dụng FromJSON thể hiện của Map String v. Một cái gì đó như sau:

{-# 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) 

Sản lượng:

[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: Bạn có thể làm điều đó mà không newtype s, tôi sử dụng chúng chỉ cho rõ ràng.

+0

Câu trả lời này rất hữu ích! Điều này có thể được sửa đổi để bỏ qua các giá trị không phải chuỗi không? (Thay thế '" 1111 "' bằng '1111', ví dụ, làm cho phân tích thành thất bại.) – davidchambers

+0

Làm thế nào một cá thể ToJSON trông giống như thế này? – AdHominem

Các vấn đề liên quan