Haskell, Aeson - Есть ли лучший способ получить нужную мне информацию из базы данных USDA? - PullRequest
0 голосов
/ 11 ноября 2018

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

Я хочу получить значение ключа "ndbno" по этой ссылке https://api.nal.usda.gov/ndb/search/?format=json&q=potato+salad&sort=n&max=25&offset=0&api_key=DEMO_KEY

Файл JSON по этой ссылке выглядит следующим образом:

{
    "list": {
        "q": "potato salad",
        "sr": "1",
        "ds": "any",
        "start": 0,
        "end": 25,
        "total": 251,
        "group": "",
        "sort": "n",
        "item": [
            {
                "offset": 0,
                "group": "Branded Food Products Database",
                "name": "AHOLD, DEVILED EGG POTATO SALAD, UPC: 688267141584",
                "ndbno": "45044170",
                "ds": "LI",
                "manu": "Ahold USA, Inc."
            },
            {
                "offset": 1,
                "group": "Branded Food Products Database",
                "name": "AHOLD, REDSKIN POTATO SALAD, UPC: 688267141591",
                "ndbno": "45044169",
                "ds": "LI",
                "manu": "Ahold USA, Inc."
                },
...

"nbdno" ключ 4-й в "item"

{-# LANGUAGE DeriveGeneric #-}

module Lib
    ( someFunc
    ) where


import           Data.Aeson
import           Data.HashMap.Strict  as HS
import           Data.List            as L
import           Data.Maybe
import           Data.Text
import           Data.Vector          as V
import           GHC.Generics
import           Network.HTTP.Conduit
import           Text.Pretty.Simple


data Food = Name (String, Text)
          | Stuff (String, Int)
    deriving (Eq, Read, Show, Generic)



someFunc :: IO ()
someFunc = putStrLn "Under Consruction!"


apiKey = "https://api.nal.usda.gov/ndb/search/?format=json&q=chana+dal&sort=n&max=25&offset=0&api_key=jJN9dsKFe507qjLVqbecijtrYB4AiojXVIt1EaEZ"


instance FromJSON Food


unString x = case x of
  String x -> x

unObject x = case x of
  Object x -> x

unArray x = case x of
  Array x -> x


getParsed :: IO ()
getParsed = do
  x <- simpleHttp apiKey
  let y = (unObject . snd . L.head . HS.toList . fromJust) (decode x :: Maybe Object)
      z = (unArray . snd . L.last . L.init) (HS.toList y)
      a = V.map (unpack . unString . snd . L.head . L.drop 5 . HS.toList . unObject) z
      b = V.map (\x -> read x :: Int) a
  pPrint b

То, как я это реализовал, довольно грязно, но оно выполняет свою работу.

Просто код выглядит очень плохо и почти невозможно прочитать. Поэтому мне было интересно, есть ли лучший способ сделать это.

1 Ответ

0 голосов
/ 11 ноября 2018

Определите типы, которые вы хотите десериализовать, например:

{-# LANGUAGE DeriveGeneric #-}
module Q53251928 where

import Data.Aeson
import GHC.Generics

data Item = Item { ndbno :: String } deriving (Eq, Show, Generic)
instance FromJSON Item

data FoodStuff = FoodStuff { item :: [Item] } deriving (Eq, Show, Generic)
instance FromJSON FoodStuff

data RootJSON = RootJSON { list :: FoodStuff } deriving (Eq, Show, Generic)
instance FromJSON RootJSON

Эти типы являются минимальными типами, необходимыми для доступа ко всем значениям ndbno. Вы можете добавить другие метки к типам для захвата других данных, например, group, start, end и т. Д.

Я скачал файл по ссылке и попытался декодировать его из GHCi, который работал нормально:

*Q53251928 Q53251928> decodeFileStrict "download.json" :: IO (Maybe RootJSON)
Just (RootJSON {list = FoodStuff {item = [Item {ndbno = "45044170"},
Item {ndbno = "45044169"},Item {ndbno = "45287938"},Item {ndbno = "45314045"},
Item {ndbno = "45036851"},Item {ndbno = "45036824"},Item {ndbno = "45198766"},
Item {ndbno = "45270526"},Item {ndbno = "45270516"},Item {ndbno = "45374956"},
Item {ndbno = "45215370"},Item {ndbno = "45225694"},Item {ndbno = "45225696"},
Item {ndbno = "45217133"},Item {ndbno = "45053881"},Item {ndbno = "45270521"},
Item {ndbno = "45226407"},Item {ndbno = "45218344"},Item {ndbno = "45225703"},
Item {ndbno = "45335760"},Item {ndbno = "45221588"},Item {ndbno = "45193027"},
Item {ndbno = "45194338"},Item {ndbno = "45194331"},Item {ndbno = "45256801"}]}})
...