在不必定义“数据”类的情况下解析JSON

时间:2014-06-18 13:46:27

标签: json haskell

我向服务器发出了大量此类请求,返回JSON:

MyJsonData = MyJsonData { field1 :: String, field2 :: String }
d <- (Aeson.eitherDecode <$> simpleHttp "https://someUrl.com") :: IO (Either String MyJsonData)
print d

MyJsonData2 = MyJsonData2 { field12 :: String, field22 :: String }
d2 <- (Aeson.eitherDecode <$> simpleHttp "https://someUrl2.com") :: IO (Either String MyJsonData2)
print d2

当然,就JSON表示而言,所有服务器都返回相似但不准确的数据。我只需要从这几个字段中获取值,我不需要它们。我希望能够做到以下几点:

-- not valid Haskell code!
(d1, d2) <- (Aeson.eitherDecode <$> simpleHttp "https://someUrl.com") :: IO (Either String (_ _ _ fieldINeed _ _ fieldIneed2))
print d1
print d2

(d3, d4) <- (Aeson.eitherDecode <$> simpleHttp "https://someUrl2.com") :: IO (Either String (_ _ fieldINeed3 fieldIneed4 _ _ _))
print d3
print d4

或类似的东西。这个想法是摆脱定义data S MyJsonDataMyJsonData2等的必要性。这可能吗?

2 个答案:

答案 0 :(得分:2)

这样的事情应该有效:

output <- Aeson.eitherDecode rawData :: IO (Either String Aeson.Value)
case output of
    Right jsonValue -> case jsonValue of
        (Aeson.Object jsonObject) -> case (HashMap.lookup "someKey" jsonObject, HashMap.lookup "anotherKey" jsonObject) of
             (Just val, Just val2) -> -- Your code here
             _ -> error "Couldn't get both keys"
        _ -> error "Unexpected JSON"
    Left errorMsg -> error $ "Error in parsing: " ++ errorMsg

基本上,JSON对象只是一个HashMap,你可以操作,而JSON数组只是vector

如果您有一堆密钥,只需map HashMap.lookup一组密钥,然后在列表中运行sequence即可获得所需内容。

case (sequence $ map (\k -> HashMap.lookup k jsonObject) ["key1", "key2", "key3"]) of
    Just x -> -- Your code here
    Nothing -> error "Some key missing"

答案 1 :(得分:1)

请注意,Data.Aeson.ValueFromJSON的实例。因此,您可以解码对Value的响应,然后仅提取您需要的内容。

例如

{-# LANGUAGE OverloadedStrings #-}

import Data.Aeson
import Data.Aeson.Types
import Control.Monad

parser1 :: Value -> Parser (String, String)
parser1 (Object o) = do
  str1 <- o .: "str1"
  str2 <- o .: "str2"
  return (str1, str2)
parser1 _ = mzero

parser2 :: Value -> Parser (String, String)
parser2 (Object o) = do
  str1 <- o .: "string1"
  str2 <- o .: "string2"
  return (str1, str2)    
parser2 _ = mzero

main :: IO ()
main = do
  let json1 = object [
        "str1" .= ("world" :: String),
        "str2" .= ("12" :: String),
        "other" .= (12.5 :: Float)
        ]
  let json2 = object [
        "string1" .= ("world" :: String),
        "string2" .= ("12" :: String),
        "other" .= (12.5 :: Float)
        ]
  print $ parseEither parser1 json1
  print $ parseEither parser2 json2

ADD: 您可以使用字段名称参数化解析器:

parser :: (Text, Text) -> Value -> Parser (String, String)
parser (f1, f2) (Object o) = do
  str1 <- o .: f1
  str2 <- o .: f2
  return (str1, str2)
parser _ _ = mzero
...
print $ parseEither (parser ("str1", "str2")) json1
print $ parseEither (parser ("string1", "string2")) json2