Во-первых: Aeson не самая простая библиотека для новичка .Конечно, есть и более сложные, но они предполагают, что вы уже достаточно много говорите о языке.Вы не выбрали «простейшую задачу» для начала.Я знаю, что это может быть удивительно, и вы можете подумать, что синтаксический анализ JSON должен быть простым, но синтаксический анализ JSON с надежными гарантиями типов на самом деле не так прост.
Но вот что я могу вам сказать, чтобы помочь вам немного:
Сначала используйте eitherDecode
вместо decode
: вместо сообщения Nothing
вы получите сообщение об ошибке, которое немного вам поможет.
Получение с помощью Generic
аккуратно и очень часто экономит время, но это также не волшебство.Имя ключа объекта и имя ваших полей типов данных должны точно совпадать.К сожалению, это не тот случай, и из-за синтаксиса haskell вы не можете назвать свои поля как ключи объекта.Лучшее решение - внедрить FromJSON вручную (см. Рекомендованную ссылку ниже).Хороший способ увидеть «что ожидается» от универсального FromJSON - это также получить ToJSON, создать фиктивную Quote
и посмотреть результат encode
.
Ваше первое поле(quote
) - это не ключ самого объекта, а имя этого объекта.Таким образом, у вас есть динамические ключи (здесь есть глобальная цитата).Еще раз, это обычно тот случай, когда вы хотите написать экземпляр FromJSON вручную.
Я рекомендую вам прочитать этот знаменитый учебник , написанный Артемом Казаком для Aeson.Это очень поможет вам и, вероятно, будет лучшим советом, который я могу дать.
Для вашего ручного примера, предположим, что это был точно документ, который вы хотите проанализировать, и у вас была только "Глобальная цитата"«чтобы иметь дело с этим, это выглядело бы более или менее так:
instance ToJSON Quote where
parseJSON = withObject "Document" $
\d -> do
glob <- d .: "Global Quote"
withObject "Quote" v (\gq ->
Quote <$> gq .: "01. symbol"
<*> pure "Global Quote"
<*> gq .: "02. open"
<*> gq .: "03. high"
-- ... and so on
) v
(Это не самый красивый и не лучший способ написать это, но это должен быть один из возможных способов).
Также обратите внимание, что, как писал проницательный комментатор, типы ваших полей не всегда совпадают с типом вашего примера JSON-документа.«volume» - это Int
(целое число, ограниченное байтами), потенциально Integer
(«математическое» целое число, без ограничений), но не Float
.Ваш "ltd" может быть проанализирован на строку - но это, вероятно, должна быть дата (Day
из Data.Time
будет первым выбором - у него уже есть экземпляр FromJSON
, поэтому есть вероятность, что он должен быть разобран как есть).Процент изменений, скорее всего, не разбирается как Float, поэтому вам нужно написать специальный анализатор для этого типа (и решить, как вы хотите его сохранить - Ratio
- это потенциальное решение).