Cosider以下JSON结构:
{"k1":
{"k2":
[{"a": 3, "b": 4, "c": 2},
{"a": 1, "b": 2, "c": 9}]},
"irrelevant": "x"}
和Haskell数据类型:
data My = My Int Int
上面的JSON应该解析为My:[My]
的List,而两个Int应该从JSON数组的“a”和“b”键中取出:
[My 3 4, My 1 2]
不可否认,我已经面临着最简单部分的麻烦。
以下是我开始使用Aeson的方式:
import Data.Aeson
import qualified Data.ByteString.Lazy.Char8 as L8
sample :: L8.ByteString
sample = "{\"k1\":{\"k2\":[{\"a\": 3, \"b\": 4, \"c\": 2}, {\"a\": 1, \"b\": 2, \"c\": 9}]}, \"irrelevant\": \"x\"} "
在repl:
decode sample :: Maybe Object
Just (Object (fromList [("irreleva...
这可以正常工作,解析JSON。但是,下一步,将对象设置为键“k1”不起作用:
:t (fromJust $ (decode sample :: Maybe Object)) .: "k1"
...
:: FromJSON a => aeson-0.11.2.1:Data.Aeson.Types.Internal.Parser a
我在这里收到Parser a
类型,此时我需要/期望获得另一个Object
或Maybe Object
。
我是在正确的道路上吗?
答案 0 :(得分:0)
我将从头开始然后回到你的问题。
使用课程解决
通常,您为每个JSON类型创建一个Haskell数据类型,并编写实现解析器的FromJSON
类。你没有必要,但它确实减轻了心理负担,并与你在其他项目中观察到的内容一致。为此,我们只为您的元素制作一些My
类型,为Mys
制作这些元素的列表:
{-# LANGUAGE OverloadedStrings #-}
import Data.Aeson
import qualified Data.ByteString.Lazy.Char8 as L8
import qualified Data.Vector as V
sample :: L8.ByteString
sample = "{\"k1\":{\"k2\":[{\"a\": 3, \"b\": 4, \"c\": 2}, {\"a\": 1, \"b\": 2, \"c\": 9}]}, \"irrelevant\": \"x\"} "
newtype Mys = Mys [My]
deriving (Eq,Ord,Show)
data My = My Int Int
deriving (Eq,Ord,Show)
好的,没问题。现在,我们可以从您的k1
记录中提取abc对象的列表,并在这些对象上运行My
解析器,以获得a
和b
值:
instance FromJSON Mys where
parseJSON (Object v) = do
do k1Val <- v .: "k1"
case k1Val of
Object k1 ->
do k2Val <- k1 .: "k2"
Mys . V.toList <$> mapM parseJSON k2Val
_ -> fail "k1 was not an Object"
parseJSON o = fail $ "Invalid type for Mys: " ++ show o
也就是说,要解析Mys
我们需要一个对象,该对象必须有一个k1
条目,这是另一个对象。 k1
必须有一个k2
条目,我们可以将其Vector
My
分析为instance FromJSON My where
parseJSON (Object v) = My <$> v .: "a" <*> v .: "b"
parseJSON o = fail $ "Invalid type for My: " ++ show o
。
My
a
数据只是将b
和Int
字段解析为> decode sample :: Maybe Mys
Just (Mys [My 3 4,My 1 2])
。看哪:
:t (fromJust $ (decode sample :: Maybe Object)) .: "k1"
没有课程
您问过.:
,这只是询问> :t (.:)
(.:) :: FromJSON a => Object -> Text -> Parser a
类型的一种奇特方式:
Parser
正如你所说,所以你提供了一个对象和文本来获得Parser
。我不建议再次使用decode
monad - 您实际上只是将其用于case
。总之,我说不,你没有走上幸福之路。
如果您未按设计使用API,则只需忘记组合器并直接使用数据类型。也就是说,Value
类型的Object
被破坏了很多。首先是k1,它是HashMap
(只是一个Array
)然后提取k2值,这是Vector
(a a
),最后对于Vector的每个元素你再次提取一个Object并在那里查找b
和Maybe
个键。我打算写一下这个例子,但是如果你不至少允许自己$(document).ready(function(){
var bquestionname = $.trim($("#questionname").val());
alert(bquestionname);
$('#google_login').oauthpopup({
path: rootUrl+'social/login.php?google&bquestionname='+bquestionname,
width:650,
height:350,
});
});
monad那就非常难看。
答案 1 :(得分:0)
教程'Aeson: the tutorial' by Artyom可以帮助你,因为它帮助了我。
在它之后,我得到了以下代码。它扩展sample
以允许处理不同的样本(一些具有各种缺陷)。 main
期望将要处理的样本的标识作为已编译可执行文件的第一个参数提供。
从JSON结构的底部开始,向上工作,函数parseMy :: Value -> Parser My
处理一个对象&#39; a&#39; &#39; B&#39;产生My
的钥匙(如果成功的话);中间辅助函数parseMyList'
处理此类对象的数组以生成My
的列表;并parseMyList
使用键&#39; k1&#39;处理一个对象,然后依次产生一个带有键&#39;&#39;的对象,以产生一个My
的列表。
在main
中,parse
将parseMyList :: Value -> Parser [My]
应用于decode
的结果(如果成功)。
{-# LANGUAGE OverloadedStrings #-}
module Main (main) where
import Data.Aeson ((.:), decode, Value)
import Data.Aeson.Types (parse, Parser, withArray, withObject)
import qualified Data.ByteString.Lazy.Char8 as L8 (ByteString)
import qualified Data.Vector as V (toList)
import System.Environment (getArgs)
data My = My Int Int deriving (Show)
sample :: String -> L8.ByteString
sample "1" = "{\"k1\":{\"k2\":[{\"a\": 3, \"b\": 4, \"c\": 2}, {\"a\": 1, \"b\": 2, \"c\": 9}]}, \"irrelevant\": \"x\"} "
sample "2" = "{\"k1\":{\"k2\":[{\"a\": 3, \"b\": 4, \"c\": 2}, {\"a\": 1, \"c\": 9}]}, \"irrelevant\": \"x\"} "
sample "3" = "{\"k1\":{\"k3\":[{\"a\": 3, \"b\": 4, \"c\": 2}, {\"a\": 1, \"b\": 2, \"c\": 9}]}, \"irrelevant\": \"x\"} "
sample "4" = "{\"k1\":{\"k2\":[{\"a\": 3, \"b\": 4, \"c\": 2}]}, \"irrelevant\": \"x\"} "
sample _ = "Error"
parseMy :: Value -> Parser My
parseMy = withObject "object" $ \o -> do
a <- o .: "a"
b <- o .: "b"
return $ My a b
parseMyList' :: Value -> Parser [My]
parseMyList' = withArray "array" $ \arr ->
mapM parseMy (V.toList arr)
parseMyList :: Value -> Parser [My]
parseMyList = withObject "object" $ \o -> do
k1 <- o .: "k1"
k2 <- k1 .: "k2"
parseMyList' k2
main :: IO ()
main = do
args <- getArgs
case args of
[] -> fail "expected sample identity as the first argument"
n:_ -> do
putStrLn $ "Processing sample " ++ n
case decode (sample n) of
Just result -> print $ parse parseMyList result
Nothing -> fail "decoding failed"