{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE RankNTypes #-} module AWS.Lib.Parser where import Data.XML.Types (Event(..), Name(..)) import Data.Text (Text) import qualified Data.Text as T import Data.Conduit import qualified Data.Conduit.List as CL import qualified Text.XML.Stream.Parse as XML import Control.Applicative text :: MonadThrow m => GLSink Event m Text text = XML.content itemConduit :: MonadThrow m => Text -> GLSink Event m o -> GLConduit Event m o itemConduit tag inner = maybe (()) id <$> elementM tag (listConduit "item" inner) listConduit :: MonadThrow m => Text -> GLSink Event m o -> GLConduit Event m o listConduit name p = awaitWhile isTag >>= maybe (return ()) (\e -> do leftover e if isBeginTagName name e then do element name $ p >>= yield listConduit name p else return () ) listConsumer :: MonadThrow m => Text -> GLSink Event m o -> GLSink Event m [o] listConsumer name p = listConduit name p >+> CL.consume itemsSet :: MonadThrow m => Text -> GLSink Event m o -> GLSink Event m [o] itemsSet tag inner = itemConduit tag inner >+> CL.consume isTag :: Event -> Bool isTag (EventBeginElement _ _) =True isTag (EventEndElement _) =True isTag _ = False sinkDropWhile :: Monad m => (i -> Bool) -> GLSink i m () sinkDropWhile f = await >>= maybe (return ()) g where g i | f i = sinkDropWhile f | otherwise = leftover i >> return () isBeginTagName :: Text -> Event -> Bool isBeginTagName name (EventBeginElement n _) | nameLocalName n == name = True | otherwise = False isBeginTagName _ _ = False awaitWhile :: Monad m => (i -> Bool) -> Pipe l i o u m (Maybe i) awaitWhile f = await >>= g where g Nothing = return Nothing g (Just a) | f a = return $ Just a | otherwise = awaitWhile f getF :: MonadThrow m => Text -> (Text -> b) -> Pipe Event Event o u m b getF name f = tagContent name >>= return . f getT :: MonadThrow m => Text -> Pipe Event Event o u m Text getT name = getF name id getM :: MonadThrow m => Text -> (Maybe Text -> b) -> Pipe Event Event o u m b getM name f = tagContentM name >>= return . f getMT :: MonadThrow m => Text -> Pipe Event Event o u m (Maybe Text) getMT name = getM name id elementM :: MonadThrow m => Text -> Pipe Event Event o u m a -> Pipe Event Event o u m (Maybe a) elementM name inner = do sinkDropWhile $ not . isTag XML.tagPredicate g (return ()) $ const inner where g n = (nameLocalName n == name) element :: MonadThrow m => Text -> Pipe Event Event o u m a -> Pipe Event Event o u m a element name inner = XML.force "parse error" $ elementM name inner tagContentM :: MonadThrow m => Text -> GLSink Event m (Maybe Text) tagContentM name = elementM name text tagContent :: MonadThrow m => Text -> GLSink Event m Text tagContent name = XML.force ("parse error:" ++ T.unpack name) $ tagContentM name