packages feed

hexml-lens-0.2.0: examples/courses.hs

{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE RecordWildCards       #-}
{-# OPTIONS -Wno-unused-top-binds #-}

import           Control.Applicative
import qualified Control.Category           as C
import           Control.Lens               hiding (children)
import qualified Data.ByteString.Lazy.Char8 as LB
import           Network.Wreq
import           Text.XML.Hexml
import           Text.XML.Hexml.Lens

url,url2 :: String
url = "http://aiweb.cs.washington.edu/research/projects/xmltk/xmldata/data/courses/reed.xml"
url2 = "http://aiweb.cs.washington.edu/research/projects/xmltk/xmldata/data/courses/uwm.xml"
url_local  = "/Users/pepe/Downloads/reed.xml"
url2_local = "/Users/pepe/Downloads/uwm.xml"

type Strings = String

data Place s = Place
  { building :: s
  , room     :: Int
  }
  deriving Show

data Course s = Course
  { title      :: s
  , instructor :: Maybe s
  , place      :: Maybe (Place s)
  , sections   :: [Section s]
  }
  deriving Show

data Section s = Section
  { name       :: s
  , days       :: s
  , start, end :: s
  , instructor :: s
  }
  deriving Show

main :: IO ()
main = do
  r <- get url2_local
  let courses = take 10 $ r ^.. responseBody . to stripDocTypeB . _XML . node "course_listing" . courseF
  print courses

stripDocTypeB :: LB.ByteString -> LB.ByteString
stripDocTypeB = LB.unlines . drop 2 . LB.lines
stripDocType :: String -> String
stripDocType = unlines . drop 2 . lines

courseF :: Fold Node (Course Strings)
courseF = runFold $ do
  title <- field "title"
  instructor <- optional $ field "instructor"
  place <- optional $ Fold $ node "place" . placeF
  sections <- Fold $ many $ node "section_listing" . sectionF
  return Course{..}

sectionF :: Fold Node (Section Strings)
sectionF = runFold $ do
  instructor <- field "instructor"
  name <- field "section"
  days <- field "days"
  (start, end) <- Fold $ node "hours" . runFold hoursF
  return Section{..}

hoursF :: ReifiedFold Node (Strings, Strings)
hoursF = (,) <$> field "start" <*> field "end"

placeF :: Fold Node (Place Strings)
placeF = runFold $ do
  building <- field "building"
  room     <- Fold _Show C.. field "room"
  return (Place building room)

field :: (XML a, XML t) => t -> ReifiedFold Node a
field n = Fold $ node n . _inner