@@ -2,7 +2,7 @@ module Text.XML.DOM.Parser.Combinators
22 ( -- * Generic combinators to traverse descendants
33 traverseElems
44 , inFilteredTrav
5− -- * Using 'DomTraversable'
5+ -- * Using 'Buildable'
66 , inElemTrav
77 , inElem
88 , inElemAll
@@ -22,24 +22,23 @@ import Control.Monad.Reader
2222import Data.Foldable as F
2323import Data.List as L
2424import Data.List.NonEmpty (NonEmpty(..))
25−import Data.Monoid
2625import Data.Text as T
2726import Data.Traversable
2827import Text.XML
29−import Text.XML.DOM.Parser.Common
28+import Text.XML.DOM.Parser.Buildable
3029import Text.XML.DOM.Parser.Types
3130import Text.XML.Lens
3231
3332
34−-- | Generic function to traverse arbitrary inner cursors.
33+-- | Generic function to traverse arbitrary inner elements.
3534traverseElems
3635 :: (Monad m, Foldable g, Traversable f)
3736 => ([Element] -> DomParserT g m (f (DomPath, Element)))
3837 -- ^ Takes list of current elements and returns container with
39− -- pairs of subpath (relatively to current element) and element
38+ -- pairs of subpath (relatively to current elements) and element
4039 -- to run parser in
4140 -> DomParserT Identity m a
42− -- ^ Parser will be runned for each element found in traversable
41+ -- ^ Parser to run for each element found in traversable 'f'
4342 -> DomParserT g m (f a)
4443traverseElems trav parser = do
4544 pd <- ask
@@ -49,15 +48,15 @@ traverseElems trav parser = do
4948 newpd = ParserData
5049 { _pdElements = Identity e
5150 , _pdPath = pd ^. pdPath <> subpath }
52− -- type of reader has been changed, local won't work here
53− magnify (to $ const newpd) parser
51+ lift $ runReaderT parser newpd
5452
55−-- | Takes function filtering
53+-- | Traverses elements located in same path using filtering function
5654inFilteredTrav
5755 :: (Monad m, Foldable g, Buildable f)
5856 => ([Element] -> (DomPath, [Element]))
59− -- ^ Function returning some filtered elements with path suffixes which will
60− -- be appended to parser's state
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
6160 -> DomParserT Identity m a
6261 -> DomParserT g m (f a)
6362inFilteredTrav deeper = traverseElems trav
@@ -68,49 +67,54 @@ inFilteredTrav deeper = traverseElems trav
6867 Nothing -> throwParserError $ PENotFound . (<> path)
6968 Just tr -> return $ fmap (path,) tr
7069
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.
7174inElemTrav
7275 :: (Monad m, Foldable g, Buildable f)
73− => NameMatcher -- ^ Name of tag to traverse in
76+ => ElemMatcher -- ^ Tag(s) matcher to traverse in
7477 -> DomParserT Identity m a
7578 -> DomParserT g m (f a)
7679inElemTrav n = inFilteredTrav deeper
7780 where
78− deeper = (DomPath [_nmShow n],) . toListOf (folded . nodes . folded . _Element . elMatchName n)
81+ elemsFold = folded . nodes . folded . _Element . elMatch n
82+ deeper = (DomPath [_emShow n],) . toListOf elemsFold
7983
80−-- | Runs parser inside first children element with given name
84+-- | Runs parser inside first children element matched by macher
8185inElem
8286 :: (Monad m, Foldable g)
83− => NameMatcher
87+ => ElemMatcher
8488 -> DomParserT Identity m a
8589 -> DomParserT g m a
8690inElem n = fmap runIdentity . inElemTrav n
8791
8892inElemAll
8993 :: (Monad m, Foldable g)
90− => NameMatcher
94+ => ElemMatcher
9195 -> DomParserT Identity m a
9296 -> DomParserT g m [a]
9397inElemAll = inElemTrav
9498
9599inElemMay
96100 :: (Monad m, Foldable g)
97− => NameMatcher
101+ => ElemMatcher
98102 -> DomParserT Identity m a
99103 -> DomParserT g m (Maybe a)
100104inElemMay = inElemTrav
101105
102106inElemNe
103107 :: (Monad m, Foldable g)
104− => NameMatcher
108+ => ElemMatcher
105109 -> DomParserT Identity m a
106110 -> DomParserT g m (NonEmpty a)
107111inElemNe = inElemTrav
108112
109113{- | Dive given parser's current tags set into the given path. The @divePath
110−["a", "b"]@ differs from @inElem "a" . inElem "b"@. Namely the first variant
114+["a", "b"]@ differs from @inElem "a" $ inElem "b"@. Namely the first variant
111115will not fail if occured tag "a" which does not contains tag "b". This
112116behaviour is desireable when you dont want to parse whole XML and just want
113−to pull tags in some path. The other difference is in traversing inner
117+to pull tags located in some path. The other difference is in traversing inner
114118elements. Consider this code
115119
116120@
@@ -128,26 +132,31 @@ which translates like: @a > b > c > fromDom@
128132As you can see, inElem always takes first element and runs inner parser in this
129133single element, unlike 'divePath' which runs inner parser @in all@ descendants
130134in 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.
131140-}
132141
133142divePath
134143 :: forall m g a
135144 . (Monad m, Foldable g)
136− => [NameMatcher]
145+ => [ElemMatcher]
137146 -> DomParserT [] m a
138147 -> DomParserT g m a
139148divePath path = magnify $ to modElems
140149 where
141150 modElems
142151 = over pdElements (toListOf $ folded . diver)
143− . over pdPath (<> DomPath (L.map _nmShow path))
152+ . over pdPath (<> DomPath (L.map _emShow path))
144153 diver :: Fold Element Element
145154 diver = F.foldr (.) id $ L.map toDive path
146− toDive n = nodes . folded . _Element . elMatchName n
155+ toDive n = nodes . folded . _Element . elMatch n
147156
148157diveElem
149158 :: (Monad m, Foldable g)
150− => NameMatcher
159+ => ElemMatcher
151160 -> DomParserT [] m a
152161 -> DomParserT g m a
153162diveElem p = divePath [p]
@@ -188,6 +197,6 @@ ignoreBlank = ignoreElem test
188197 let
189198 elems = e ^.. nodes . folded . _Element
190199 cont = mconcat $ e ^.. nodes . folded . _Content
191− in if | not $ L.null elems -> False
200+ in if | not $ L.null elems -> False
192201 | T.null $ T.strip cont -> True
193202 | otherwise -> False