Разбор списка с вложенным списком с помощью Aeson - PullRequest
0 голосов
/ 08 декабря 2018

При попытке проанализировать несколько простых JSON с помощью Aeson я получаю ошибку типа, которую я не понимаю.У меня есть следующий JSON

jsonString = "[\"a\", [\"b\", \"c\"]]" :: L.ByteString

, и я определил следующий импорт и код:

import Data.Aeson
import GHC.Generics
import qualified Data.ByteString.Lazy as L

data Ch = Ch {
   c1 :: String,
   c2 :: (String, String)
} deriving (Show, Generic)
instance FromJSON Ch

Когда я пытаюсь использовать eitherDecode в этой строке с моим типом ChЯ получаю сообщение об ошибке

*Aeson> eitherDecode jsonString :: Either String Ch
Left "Error in $: expected record (:*:), encountered Array"

Может кто-нибудь объяснить мне ошибку и сказать, как я должен проанализировать этот JSON?

Подход, который будет работать, это

eitherDecode jsonString :: Either String (String, (String, String))

, но я бы предпочел перейти к своему типу напрямую.

1 Ответ

0 голосов
/ 08 декабря 2018

Если вы уже знаете о типе, который анализирует по назначению, то, возможно, самое простое решение - просто написать свой экземпляр в терминах этого типа и перевести:

import Data.Aeson
import GHC.Generics
import qualified Data.ByteString.Lazy as L

data Ch = Ch {
   c1 :: String,
   c2 :: (String, String)
} deriving (Show, Generic)

instance FromJSON Ch where
    parseJSON x =
        do (a,(b,c)) <- parseJSON x
           pure (Ch a (b,c))

И результат:

*Main> :set -XOverloadedStrings
*Main> eitherDecode "[\"a\", [\"b\", \"c\"]]" :: Either String Ch
Right (Ch {c1 = "a", c2 = ("b","c")})

РЕДАКТИРОВАТЬ:

Более прямое использование API Aeson может быть информативным или предпочтительным:

instance FromJSON Ch where
    parseJSON =
       withArray "Ch" $ \arr ->
       -- from Data.Aeson.Types
           if V.length arr /= 2
              -- ^ from Data.Vector
              then typeMismatch "Length should be 2" (Array arr)
                   -- ^ from Data.Aeson.Types
              else Ch <$> parseJSON (arr ! 0) <*> parseJSON ( arr ! 1 )        
...