import System(getArgs) import Char(toLower) import List(find) import Maybe(mapMaybe) import IO(hPutStrLn, stderr) import Get(readURL) import Text.XML.Light data RSSChannel = RSSChannel { chTitle :: String , chLink :: String , chItems :: Int } deriving Show getRSSChannels :: Element-> Either String [RSSChannel] getRSSChannels (Element{elName= qn, elAttribs= as , elContent= cont}) | qne qn "rss" = case lookupAttr (qname "version") as of Just v | v == "2.0" || v == "2.0.1" -> Right (getChannels cont) Just v -> Left ("Wrong RSS version "++ v) Nothing -> Right (getChannels cont) | otherwise = Left "Not an RSS feed (no top RSS element)" qne :: QName-> String-> Bool qne qn str = qName qn == str getChannels :: [Content]-> [RSSChannel] getChannels cs = mapMaybe getChannel cs getChannel :: Content-> Maybe RSSChannel getChannel (Elem e) | qne (elName e) "channel" = Just (foldr getChannelData mtChannel (elContent e)) getChannel _ = Nothing mtChannel = RSSChannel "" "" 0 getChannelData :: Content -> RSSChannel-> RSSChannel getChannelData (Elem e) ch | qne (elName e) "title" = ch{chTitle = strContent e} | qne (elName e) "item" = ch{chItems = 1+ chItems ch} | qne (elName e) "link" = ch{chLink = strContent e} getChannelData _ ch = ch processChannels :: [RSSChannel]-> Int processChannels chs = sum (map chItems chs) qname :: String-> QName qname s = QName{qName = s, qURI = Nothing, qPrefix = Nothing} sattr :: String-> String-> Attr sattr a v = Attr{attrKey= qname a, attrVal= v} selem :: String-> [Content]-> Element selem n cs = Element { elName= qname n, elAttribs= [] , elContent = cs, elLine= Nothing } text :: String-> Content text txt = Text (CData {cdVerbatim=CDataText, cdData= txt, cdLine= Nothing}) htmlHeader :: String-> [Content]-> Element htmlHeader tn cont = Element{ elName=qname "html" , elAttribs= [sattr "xmlns" "http://www.w3.org/1999/xhtml"] , elContent= map Elem [title, body] , elLine= Nothing } where title = selem "head" [Elem (selem "title" [text tn])] body = selem "body" cont showResult :: Int-> String showResult n = ppTopElement (htmlHeader "Ergebnis" [ text "Es wurden ", Elem (selem "b" [text (show n)]), text " Artikel gefunden." ]) main = do feeds <- getArgs chs <- mapM processFeed feeds putStrLn (showResult (processChannels (concat chs))) processFeed :: String-> IO [RSSChannel] processFeed link = do cont <- readURL link if null cont then return [] else case parseXMLDoc cont of Just e -> do case getRSSChannels e of Right chs -> return chs Left err -> do putStrLn $ link ++ ": "++ err; return [] Nothing -> do putStrLn $ "Can't parse \""++ show link++ "\". " return []