summaryrefslogtreecommitdiff
path: root/dht/Presence/Nesting.hs
diff options
context:
space:
mode:
Diffstat (limited to 'dht/Presence/Nesting.hs')
-rw-r--r--dht/Presence/Nesting.hs86
1 files changed, 86 insertions, 0 deletions
diff --git a/dht/Presence/Nesting.hs b/dht/Presence/Nesting.hs
new file mode 100644
index 00000000..cf47c9fc
--- /dev/null
+++ b/dht/Presence/Nesting.hs
@@ -0,0 +1,86 @@
1{-# LANGUAGE FlexibleContexts #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Nesting where
4
5import Control.Monad.State.Strict
6import Data.Conduit
7import Data.Conduit.Lift
8import qualified Data.List as List
9import qualified Data.Text as S
10import Data.XML.Types
11
12type Lang = S.Text
13
14data StrictList a = a :! !(StrictList a) | StrictNil
15
16data XMLState = XMLState {
17 nestingLevel :: Int,
18 langStack :: StrictList (Int,Lang)
19}
20
21type NestingXML o m a = ConduitM Event o (StateT XMLState m) a
22
23doNestingXML :: Monad m => NestingXML o m r -> ConduitM Event o m r
24doNestingXML m =
25 evalStateC (XMLState 0 StrictNil) (trackNesting .| m)
26
27nesting :: Monad m => NestingXML o m Int
28nesting = lift $ (return . nestingLevel) =<< get
29
30xmlLang :: Monad m => NestingXML o m (Maybe Lang)
31xmlLang = fmap (fmap snd . top . langStack) (lift get)
32 where
33 top ( a :! _as ) = Just a
34 top _ = Nothing
35
36trackNesting :: Monad m => ConduitM Event Event (StateT XMLState m) ()
37trackNesting = awaitForever doit
38 where
39 doit xml = do
40 XMLState lvl langs <- lift get
41 lift . put $ case xml of
42 EventBeginElement _ attrs ->
43 case lookupLang attrs of
44 Nothing -> XMLState (lvl+1) langs
45 Just lang -> XMLState (lvl+1) ( (lvl+1,lang) :! langs)
46 EventEndElement _ ->
47 case langs of
48 (llvl,_) :! ls | llvl==lvl -> XMLState (lvl-1) ls
49 _ | otherwise -> XMLState (lvl-1) langs
50 _ -> XMLState lvl langs
51 yield xml
52
53
54lookupLang :: [(Name, [Content])] -> Maybe S.Text
55lookupLang attrs =
56 case List.find ( (=="xml:lang") . fst) attrs of
57 Just (_,[ContentText x]) -> Just x
58 Just (_,[ContentEntity x]) -> Just x
59 _ -> Nothing
60
61
62awaitCloser :: Monad m => Int -> NestingXML o m ()
63awaitCloser lvl =
64 fix $ \loop -> do
65 lvl' <- nesting
66 when (lvl' >= lvl) $ do
67 xml <- await
68 maybe (return ()) (const loop) xml
69
70withXML ::
71 Monad m =>
72 (i -> ConduitM i o m ()) -> ConduitM i o m ()
73withXML f = await >>= maybe (return ()) f
74
75nextElement :: Monad m => NestingXML o m (Maybe Event)
76nextElement = do
77 lvl <- nesting
78 fix $ \loop -> do
79 xml <- await
80 case xml of
81 Nothing -> return Nothing
82 Just (EventBeginElement _ _) -> return xml
83 Just _ -> do
84 lvl' <- nesting
85 if (lvl'>=lvl) then loop
86 else return Nothing