From 7ccaa169bc2309df7df2db118dd646177867f2b0 Mon Sep 17 00:00:00 2001 From: joe Date: Wed, 12 Feb 2014 20:35:52 -0500 Subject: Reply to pings with pongs. --- Presence/Nesting.hs | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 Presence/Nesting.hs (limited to 'Presence/Nesting.hs') diff --git a/Presence/Nesting.hs b/Presence/Nesting.hs new file mode 100644 index 00000000..24f9baad --- /dev/null +++ b/Presence/Nesting.hs @@ -0,0 +1,79 @@ +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE FlexibleContexts #-} +module Nesting where + +import Data.Conduit +import Data.Conduit.Lift +import Data.XML.Types +import qualified Data.Text as S +import Control.Monad.State +import qualified Data.List as List + +type Lang = S.Text + +data StrictList a = a :! !(StrictList a) | StrictNil + +data XMLState = XMLState { + nestingLevel :: Int, + langStack :: StrictList (Int,Lang) +} + +type NestingXML o m a = ConduitM Event o (StateT XMLState m) a + +doNestingXML :: Monad m => NestingXML o m r -> ConduitM Event o m r +doNestingXML m = + evalStateC (XMLState 0 StrictNil) (trackNesting =$= m) + +nesting :: Monad m => NestingXML o m Int +nesting = lift $ (return . nestingLevel) =<< get + + +trackNesting :: Monad m => ConduitM Event Event (StateT XMLState m) () +trackNesting = awaitForever doit + where + doit xml = do + XMLState lvl langs <- lift get + lift . put $ case xml of + EventBeginElement _ attrs -> + case lookupLang attrs of + Nothing -> XMLState (lvl+1) langs + Just lang -> XMLState (lvl+1) ( (lvl+1,lang) :! langs) + EventEndElement _ -> + case langs of + (llvl,_) :! ls | llvl==lvl -> XMLState (lvl-1) ls + _ | otherwise -> XMLState (lvl-1) langs + _ -> XMLState lvl langs + yield xml + + +lookupLang attrs = + case List.find ( (=="xml:lang") . fst) attrs of + Just (_,[ContentText x]) -> Just x + Just (_,[ContentEntity x]) -> Just x + _ -> Nothing + + +awaitCloser :: Monad m => Int -> NestingXML o m () +awaitCloser lvl = do + fix $ \loop -> do + lvl' <- nesting + when (lvl' >= lvl) $ do + xml <- await + maybe (return ()) (const loop) xml + +withXML f = await >>= maybe (return ()) f + +nextElement :: Monad m => NestingXML o m (Maybe Event) +nextElement = do + lvl <- nesting + fix $ \loop -> do + xml <- await + case xml of + Nothing -> return Nothing + Just (EventBeginElement _ _) -> do + return xml + Just _ -> do + lvl' <- nesting + if (lvl'>=lvl) then loop + else return Nothing + -- cgit v1.2.3