@@ -22,6 +22,7 @@ import Control.Monad.Reader
2222import Data.Foldable as F
2323import Data.List as L
2424import Data.List.NonEmpty (NonEmpty(..))
25+import Data.Monoid
2526import Data.Text as T
2627import Data.Traversable
2728import Text.XML
@@ -30,15 +31,15 @@ import Text.XML.DOM.Parser.Types
3031import Text.XML.Lens
3132
3233
33−-- | Generic function to traverse arbitrary inner elements.
34+-- | Generic function to traverse arbitrary inner cursors.
3435traverseElems
3536 :: (Monad m, Foldable g, Traversable f)
3637 => ([Element] -> DomParserT g m (f (DomPath, Element)))
3738 -- ^ Takes list of current elements and returns container with
38− -- pairs of subpath (relatively to current elements) and element
39+ -- pairs of subpath (relatively to current element) and element
3940 -- to run parser in
4041 -> DomParserT Identity m a
41− -- ^ Parser to run for each element found in traversable 'f'
42+ -- ^ Parser will be runned for each element found in traversable
4243 -> DomParserT g m (f a)
4344traverseElems trav parser = do
4445 pd <- ask
@@ -48,15 +49,15 @@ traverseElems trav parser = do
4849 newpd = ParserData
4950 { _pdElements = Identity e
5051 , _pdPath = pd ^. pdPath <> subpath }
51− lift $ runReaderT parser newpd
52+ -- type of reader has been changed, local won't work here
53+ magnify (to $ const newpd) parser
5254
53−-- | Traverses elements located in same path using filtering function
55+-- | Takes function filtering
5456inFilteredTrav
5557 :: (Monad m, Foldable g, Buildable f)
5658 => ([Element] -> (DomPath, [Element]))
57− -- ^ Takes list of current elements and returns some descendants
58− -- subset and path this descendants located at. Path is should be
59− -- same for all descendants and required for error message
59+ -- ^ Function returning some filtered elements with path suffixes which will
60+ -- be appended to parser's state. The argument is a list of current elements.
6061 -> DomParserT Identity m a
6162 -> DomParserT g m (f a)
6263inFilteredTrav deeper = traverseElems trav
@@ -67,54 +68,49 @@ inFilteredTrav deeper = traverseElems trav
6768 Nothing -> throwParserError $ PENotFound . (<> path)
6869 Just tr -> return $ fmap (path,) tr
6970
70−-- | Runs parser arbitrary times, depending on 'Buildable' instance of
71−-- 'f'. For example if 'f' becomes 'NonEmpty' then 'inElemTrav' finds
72−-- @one or more@ elements matched by given 'ElemMatcher' and run
73−-- parser in each found element, then returns @NonEmpty a@ of results.
7471inElemTrav
7572 :: (Monad m, Foldable g, Buildable f)
76− => ElemMatcher -- ^ Tag(s) matcher to traverse in
73+ => NameMatcher -- ^ Name of tag to traverse in
7774 -> DomParserT Identity m a
7875 -> DomParserT g m (f a)
7976inElemTrav n = inFilteredTrav deeper
8077 where
81− elemsFold = folded . nodes . folded . _Element . elMatch n
82− deeper = (DomPath [_emShow n],) . toListOf elemsFold
78+ deeper = (DomPath [_nmShow n],) . toListOf (folded . nodes . folded . _Element . elMatchName n)
8379
84−-- | Runs parser inside first children element matched by macher
80+-- | Runs parser inside first children element with given name
8581inElem
8682 :: (Monad m, Foldable g)
87− => ElemMatcher
83+ => NameMatcher
8884 -> DomParserT Identity m a
8985 -> DomParserT g m a
9086inElem n = fmap runIdentity . inElemTrav n
9187
9288inElemAll
9389 :: (Monad m, Foldable g)
94− => ElemMatcher
90+ => NameMatcher
9591 -> DomParserT Identity m a
9692 -> DomParserT g m [a]
9793inElemAll = inElemTrav
9894
9995inElemMay
10096 :: (Monad m, Foldable g)
101− => ElemMatcher
97+ => NameMatcher
10298 -> DomParserT Identity m a
10399 -> DomParserT g m (Maybe a)
104100inElemMay = inElemTrav
105101
106102inElemNe
107103 :: (Monad m, Foldable g)
108− => ElemMatcher
104+ => NameMatcher
109105 -> DomParserT Identity m a
110106 -> DomParserT g m (NonEmpty a)
111107inElemNe = inElemTrav
112108
113109{- | Dive given parser's current tags set into the given path. The @divePath
114−["a", "b"]@ differs from @inElem "a" $ inElem "b"@. Namely the first variant
110+["a", "b"]@ differs from @inElem "a" . inElem "b"@. Namely the first variant
115111will not fail if occured tag "a" which does not contains tag "b". This
116112behaviour is desireable when you dont want to parse whole XML and just want
117−to pull tags located in some path. The other difference is in traversing inner
113+to pull tags in some path. The other difference is in traversing inner
118114elements. Consider this code
119115
120116@
@@ -132,31 +128,26 @@ which translates like: @a > b > c > fromDom@
132128As you can see, inElem always takes first element and runs inner parser in this
133129single element, unlike 'divePath' which runs inner parser @in all@ descendants
134130in given path.
135−
136−Note also that 'divePath' takes parser parameterized by @[]@ not by
137−'Identity'. This because when you dive using some path you will get a
138−list of found elements and all these elements will be @current@ for
139−parser.
140131-}
141132
142133divePath
143134 :: forall m g a
144135 . (Monad m, Foldable g)
145− => [ElemMatcher]
136+ => [NameMatcher]
146137 -> DomParserT [] m a
147138 -> DomParserT g m a
148139divePath path = magnify $ to modElems
149140 where
150141 modElems
151142 = over pdElements (toListOf $ folded . diver)
152− . over pdPath (<> DomPath (L.map _emShow path))
143+ . over pdPath (<> DomPath (L.map _nmShow path))
153144 diver :: Fold Element Element
154145 diver = F.foldr (.) id $ L.map toDive path
155− toDive n = nodes . folded . _Element . elMatch n
146+ toDive n = nodes . folded . _Element . elMatchName n
156147
157148diveElem
158149 :: (Monad m, Foldable g)
159− => ElemMatcher
150+ => NameMatcher
160151 -> DomParserT [] m a
161152 -> DomParserT g m a
162153diveElem p = divePath [p]
@@ -197,6 +188,6 @@ ignoreBlank = ignoreElem test
197188 let
198189 elems = e ^.. nodes . folded . _Element
199190 cont = mconcat $ e ^.. nodes . folded . _Content
200− in if | not $ L.null elems -> False
191+ in if | not $ L.null elems -> False
201192 | T.null $ T.strip cont -> True
202193 | otherwise -> False