json在haskell中解析 [英] json parsing in haskell
问题描述
我试图解析haskell中的JSON数据。经过了大量的网站,这是我所能达到的最远。
data地址=地址{house :: Integer,street :: String,city :: String,state :: String,zip :: Integer}派生(显示)
数据Person = Person {name :: String,age :: Integer,address ::地址}派生(显示)
getName :: Person - > String
getName(Person n _ _)= n
getAddress :: Person - >地址
getAddress(Person _ _ a)= a
getState :: Address - > String
getState(Address _ _ _ s _)= s
文件ex.hs并加载到ghci - >
Prelude>导入Text.JSON
前奏Text.JSON> :加载前
主文本.JSON>让aa ={\name \:\some body \,\age \:23,\address \:{\house \:285 ,街道:第七大道,城市,纽约,国家,纽约 \\,zip \:10001}}
...>解码aa ::结果JSValue
它返回
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))不用说,它看起来很啰嗦(而且很可怕)。)。))))]]))
我尝试了
...>解码aa :: Result Person
它给我一个错误。我如何去从这个json字符串填充Person数据结构的实例?例如,我该如何获取JSON字符串中的人的状态......
Text.JSON
不知道如何将 JSON
数据转换为您的
Person
数据类型。为此,您需要使 Person
和实例
JSON
typeclass,或者您的罐头使用 Text.JSON.Generic
和 DeriveDataTypeable
扩展名为您完成工作。 泛型
Text.JSON.Generic
方法将读取基于数据类型
结构的 JSON
结构
{ - #LANGUAGE DeriveDataTypeable# - }
import Text.JSON.Generic
data Address = Address
{house :: Integer
,street ::字符串
,city :: String
,state :: String $ b $,zip :: Integer
}派生(显示,数据,类型化)
数据Person = Person
{name :: String
,age :: Integer
,address :: Address
}派生(Show,Data,Typeable)
aa :: String
aa ={\name \:\some body \,\age \: 23,\地址\:{\house \:285,\street \:\7th Ave. \,\city \:\纽约州\,\state \:\New York \,\zip\:10001}}
main = print(decodeJSON aa: :Person)
只要您不介意将将数据结构中的
字段添加到 JSON
格式中。 另外,您不要需要编写像 getName
, getAddress
,
和 getState
。您记录类型中字段的名称是accesor
函数。
∀x。 x⊦:t house
house ::地址 - >整数
∀x。 x⊦:t地址
地址::人物 - >地址
JSON实例
或者,您可以走高路,并实现自己的
实例 JSON
class。
import Control.Applicative
import Control.Monad
import Text.JSON
data Address = Address
{house :: Integer
,street :: String
,city :: String
,state :: String
- 重命名以免与Prelude中的zip冲突
,zipC :: Integer
}派生(显示)
数据Person = Person
{name :: String
,age :: Integer
,address :: Address
)派生(显示)
aa :: String
aa ={\name \:\some body \,\age \ :23,\address \:{\house \:285,\street \:\7th Ave. \,\city \:\ 纽约,国家 :\New York \,\zip\:10001}}
- 为了方便
(!)::(JSON a)= > JSObject JSValue - >字符串 - >结果a
(!)=翻转valFromObj
实例JSON地址其中
- 保持编译器安静
showJSON = undefined
readJSON (JSObject obj)=
地址< $>
obj! 房子< *>
obj! 街道< *>
obj! 城市< *>
obj! 状态* *
obj! zip
readJSON _ = mzero
实例JSON Person其中
- 保持编译器安静
showJSON = undefined
readJSON( JSObject obj)=
Person< $>
obj! 名称< *>
obj! 年龄< *>
obj! address
readJSON _ = mzero
main = print(decode aa :: Result Person)
这充分利用了 Result
类型轻松实现 Applicative
的优势
链接在 JSObject
值上的查询。
这是一个稍微多一点的工作,但它给了如果您必须处理会导致样式的 JSON
,那么您可以更多地控制
结构 JSON
准则
由于奇怪的字段名称而被违规。
I'm trying to parse JSON data in haskell. Having gone through a slew of websites, this is the furthest I have been able to get to.
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
I write that in a file ex.hs and load it in 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
It returns
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))]}))]}))
Needless to say, it seems pretty verbose (and frightening). I tried doing
...> decode aa :: Result Person
and it gave me an error. How do I go about populating an instance of the Person datastructure from this json string? For example, what should I do to get the state of the person in the JSON string...
The problem is that Text.JSON
does not know how to convert JSON
data to
your Person
data type. To do this, you need to either make Person
and
instance of the JSON
typeclass, or your can use Text.JSON.Generic
and the
DeriveDataTypeable
extension to do the work for you.
Generics
The Text.JSON.Generic
method will read the JSON
structure based on the
structure of your data type.
{-# 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)
This method works really well as long as you don't mind matching the names of the fields
in your data structure to your JSON
format.
As an aside, you don't need to write functions like getName
, getAddress
,
and getState
. The names of the field in your record type are accesor
functions.
∀ x. x ⊦ :t house
house :: Address -> Integer
∀ x. x ⊦ :t address
address :: Person -> Address
JSON Instance
Alternatively, you could take the high road and implement your own instance of
the JSON
class.
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)
This takes advantage of the fact that the Result
type is an Applicative
to easily
chain together queries on the JSObject
value.
This is a little more work, but it gives you more control of the structure of
the JSON
if you have to deal with JSON
that will cause style guideline
violations due to weird field names.
这篇关于json在haskell中解析的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!