json解析haskell

sha*_*har 12 json haskell haskell-platform

我正在尝试解析haskell中的JSON数据.经历了大量的网站,这是我能够达到的最远的.

data Address = Address { house :: Integer, street :: String, city :: String, state :: String, zip :: Integer } deriving (Show)
data Person = Person { name :: String, age :: Integer, address :: Address } deriving (Show)

getName :: Person -> String
getName (Person n _ _) = n

getAddress :: Person -> Address
getAddress (Person _ _ a) = a

getState :: Address -> String
getState (Address _ _ _ s _) = s
Run Code Online (Sandbox Code Playgroud)

我在ex.hs文件中写入并将其加载到ghci - >中

Prelude> import Text.JSON
Prelude Text.JSON> :load ex
Main Text.JSON> let aa = "{\"name\": \"some body\", \"age\" : 23, \"address\" : {\"house\" : 285, \"street\" : \"7th Ave.\", \"city\" : \"New York\", \"state\" : \"New York\", \"zip\" : 10001}}"
...> decode aa :: Result JSValue
Run Code Online (Sandbox Code Playgroud)

它回来了

Ok (JSObject (JSONObject {fromJSObject = [("name",JSString (JSONString {fromJSString = "some body"})),("age",JSRational False (23 % 1)),("address",JSObject (JSONObject {fromJSObject = [("house",JSRational False (285 % 1)),("street",JSString (JSONString {fromJSString = "7th Ave."})),("city",JSString (JSONString {fromJSString = "New York"})),("state",JSString (JSONString {fromJSString = "New York"})),("zip",JSRational False (10001 % 1))]}))]}))
Run Code Online (Sandbox Code Playgroud)

不用说,它似乎非常冗长(而且令人恐惧).我试过了

...> decode aa :: Result Person
Run Code Online (Sandbox Code Playgroud)

它给了我一个错误.如何从这个json字符串中填充Person数据结构的实例?例如,我该怎么做才能获得JSON字符串中人员的状态...

sab*_*uma 22

问题是Text.JSON不知道如何将JSON数据转换为您的Person数据类型.为此,您需要创建类型类的Person实例和实例JSON,或者您可以使用Text.JSON.GenericDeriveDataTypeable扩展来为您完成工作.

泛型

Text.JSON.Generic方法将JSON根据数据类型的结构读取结构.

{-# LANGUAGE DeriveDataTypeable #-}
import           Text.JSON.Generic

data Address = Address
    { house  :: Integer
    , street :: String
    , city   :: String
    , state  :: String
    , zip    :: Integer
    } deriving (Show, Data, Typeable)

data Person = Person
    { name    :: String
    , age     :: Integer
    , address :: Address
    } deriving (Show, Data, Typeable)

aa :: String
aa = "{\"name\": \"some body\", \"age\" : 23, \"address\" : {\"house\" : 285, \"street\" : \"7th Ave.\", \"city\" : \"New York\", \"state\" : \"New York\", \"zip\" : 10001}}"

main = print (decodeJSON aa :: Person)
Run Code Online (Sandbox Code Playgroud)

只要您不介意将数据结构中的字段名称与JSON格式匹配,此方法就可以正常工作.

顺便说一句,你不需要写这样的功能getName,getAddressgetState.记录类型中字段的名称是访问函数.

? x. x ? :t house
house :: Address -> Integer
? x. x ? :t address
address :: Person -> Address
Run Code Online (Sandbox Code Playgroud)

JSON实例

或者,您可以走高端路线并实施您自己的JSON班级实例.

import           Control.Applicative
import           Control.Monad
import           Text.JSON

data Address = Address
    { house  :: Integer
    , street :: String
    , city   :: String
    , state  :: String
    -- Renamed so as not to conflict with zip from Prelude
    , zipC   :: Integer
    } deriving (Show)

data Person = Person
    { name    :: String
    , age     :: Integer
    , address :: Address
    } deriving (Show)

aa :: String
aa = "{\"name\": \"some body\", \"age\" : 23, \"address\" : {\"house\" : 285, \"street\" : \"7th Ave.\", \"city\" : \"New York\", \"state\" : \"New York\", \"zip\" : 10001}}"

-- For convenience
(!) :: (JSON a) => JSObject JSValue -> String -> Result a
(!) = flip valFromObj

instance JSON Address where
    -- Keep the compiler quiet
    showJSON = undefined

    readJSON (JSObject obj) =
        Address        <$>
        obj ! "house"  <*>
        obj ! "street" <*>
        obj ! "city"   <*>
        obj ! "state"  <*>
        obj ! "zip"
    readJSON _ = mzero

instance JSON Person where
    -- Keep the compiler quiet
    showJSON = undefined

    readJSON (JSObject obj) =
        Person       <$>
        obj ! "name" <*>
        obj ! "age"  <*>
        obj ! "address"
    readJSON _ = mzero

main = print (decode aa :: Result Person)
Run Code Online (Sandbox Code Playgroud)

这利用了这样Result一个事实,即类型Applicative可以轻松地将JSObject值查询链接在一起.

这是一个更多的工作,但它可以让你更好地控制JSON你必须处理的结构,JSON这将导致由于奇怪的字段名称导致的样式指南违规.

  • [bergmark](https://github.com/silkapp/generic-aeson/issues/7):“请注意,‘Text.JSON’来自‘json’包,该包很旧,不再常用。” (2认同)

Ale*_*los 11

也许在游戏中有点晚了,但由于这是google返回的第一页,我会试一试.

如今,Aeson是事实上的标准,所以这是每个人都使用的图书馆.在埃宋TH包提供了一些不错的功能,自动生成必要的功能,为您的自定义数据类型.

基本上,您创建与json数据相对应的数据类型,然后让aeson完成魔术.

{-# LANGUAGE OverloadedStrings,TemplateHaskell #-}
import Data.Aeson
import Data.Aeson.TH
import qualified Data.ByteString.Lazy.Char8 as BL

data Address = Address
    { house  :: Integer
    , street :: String
    , city   :: String
    , state  :: Maybe String
    , zip    :: Integer
    } deriving (Show, Eq)

data Person = Person
    { name    :: String
    , age     :: Integer
    , address :: Address
    } deriving (Show, Eq)

$(deriveJSON defaultOptions ''Address)
$(deriveJSON defaultOptions ''Person)

aa :: BL.ByteString
aa = "{\"name\": \"some body\", \"age\" : 23, \"address\" : {\"house\" : 285, \"street\" : \"7th Ave.\", \"city\" : \"New York\", \"state\" : \"New York\", \"zip\" : 10001}}"

main = print (decode aa :: Maybe Person)
Run Code Online (Sandbox Code Playgroud)

您甚至可以使用Maybe数据类型的可选字段.