@@ -22,6 +22,7 @@ import Control.Monad.Reader
22import Data.Foldable as F
22import Data.Foldable as F
23import Data.List as L
23import Data.List as L
24import Data.List.NonEmpty (NonEmpty(..))
24import Data.List.NonEmpty (NonEmpty(..))
25import Data.Text as T
26import Data.Text as T
26import Data.Traversable
27import Data.Traversable
27import Text.XML
28import Text.XML
@@ -30,15 +31,15 @@ import Text.XML.DOM.Parser.Types
30import Text.XML.Lens
31import Text.XML.Lens
33−-- | Generic function to traverse arbitrary inner elements.
34+-- | Generic function to traverse arbitrary inner cursors.
34traverseElems
35traverseElems
35 :: (Monad m, Foldable g, Traversable f)
36 :: (Monad m, Foldable g, Traversable f)
36 => ([Element] -> DomParserT g m (f (DomPath, Element)))
37 => ([Element] -> DomParserT g m (f (DomPath, Element)))
37 -- ^ Takes list of current elements and returns container with
38 -- ^ 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
39 -- to run parser in
40 -- to run parser in
40 -> DomParserT Identity m a
41 -> 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
42 -> DomParserT g m (f a)
43 -> DomParserT g m (f a)
43traverseElems trav parser = do
44traverseElems trav parser = do
@@ -48,15 +49,15 @@ traverseElems trav parser = do
48 newpd = ParserData
49 newpd = ParserData
49 { _pdElements = Identity e
50 { _pdElements = Identity e
50 , _pdPath = pd ^. pdPath <> subpath }
51 , _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
53−-- | Traverses elements located in same path using filtering function
55+-- | Takes function filtering
54inFilteredTrav
56inFilteredTrav
55 :: (Monad m, Foldable g, Buildable f)
57 :: (Monad m, Foldable g, Buildable f)
56 => ([Element] -> (DomPath, [Element]))
58 => ([Element] -> (DomPath, [Element]))
57− -- ^ Takes list of current elements and returns some descendants
59+ -- ^ Function returning some filtered elements with path suffixes which will
58− -- subset and path this descendants located at. Path is should be
60+ -- be appended to parser's state. The argument is a list of current elements.
59− -- same for all descendants and required for error message
60 -> DomParserT Identity m a
61 -> DomParserT Identity m a
61 -> DomParserT g m (f a)
62 -> DomParserT g m (f a)
62inFilteredTrav deeper = traverseElems trav
63inFilteredTrav deeper = traverseElems trav
@@ -67,54 +68,49 @@ inFilteredTrav deeper = traverseElems trav
67 Nothing -> throwParserError $ PENotFound . (<> path)
68 Nothing -> throwParserError $ PENotFound . (<> path)
68 Just tr -> return $ fmap (path,) tr
69 Just tr -> return $ fmap (path,) tr
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.
75 :: (Monad m, Foldable g, Buildable f)
72 :: (Monad m, Foldable g, Buildable f)
76− => ElemMatcher -- ^ Tag(s) matcher to traverse in
73+ => NameMatcher -- ^ Name of tag to traverse in
77 -> DomParserT Identity m a
74 -> DomParserT Identity m a
78 -> DomParserT g m (f a)
75 -> DomParserT g m (f a)
79inElemTrav n = inFilteredTrav deeper
76inElemTrav n = inFilteredTrav deeper
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)
84−-- | Runs parser inside first children element matched by macher
80+-- | Runs parser inside first children element with given name
86 :: (Monad m, Foldable g)
82 :: (Monad m, Foldable g)
87− => ElemMatcher
83+ => NameMatcher
88 -> DomParserT Identity m a
84 -> DomParserT Identity m a
89 -> DomParserT g m a
85 -> DomParserT g m a
90inElem n = fmap runIdentity . inElemTrav n
86inElem n = fmap runIdentity . inElemTrav n
93 :: (Monad m, Foldable g)
89 :: (Monad m, Foldable g)
94− => ElemMatcher
90+ => NameMatcher
95 -> DomParserT Identity m a
91 -> DomParserT Identity m a
96 -> DomParserT g m [a]
92 -> DomParserT g m [a]
97inElemAll = inElemTrav
93inElemAll = inElemTrav
100 :: (Monad m, Foldable g)
96 :: (Monad m, Foldable g)
101− => ElemMatcher
97+ => NameMatcher
102 -> DomParserT Identity m a
98 -> DomParserT Identity m a
103 -> DomParserT g m (Maybe a)
99 -> DomParserT g m (Maybe a)
104inElemMay = inElemTrav
100inElemMay = inElemTrav
107 :: (Monad m, Foldable g)
103 :: (Monad m, Foldable g)
108− => ElemMatcher
104+ => NameMatcher
109 -> DomParserT Identity m a
105 -> DomParserT Identity m a
110 -> DomParserT g m (NonEmpty a)
106 -> DomParserT g m (NonEmpty a)
111inElemNe = inElemTrav
107inElemNe = inElemTrav
113{- | Dive given parser's current tags set into the given path. The @divePath
109{- | 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
115will not fail if occured tag "a" which does not contains tag "b". This
111will not fail if occured tag "a" which does not contains tag "b". This
116behaviour is desireable when you dont want to parse whole XML and just want
112behaviour 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
118elements. Consider this code
114elements. Consider this code
@@ -132,31 +128,26 @@ which translates like: @a > b > c > fromDom@
132As you can see, inElem always takes first element and runs inner parser in this
128As you can see, inElem always takes first element and runs inner parser in this
133single element, unlike 'divePath' which runs inner parser @in all@ descendants
129single element, unlike 'divePath' which runs inner parser @in all@ descendants
134in given path.
130in given path.
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
143 :: forall m g a
134 :: forall m g a
144 . (Monad m, Foldable g)
135 . (Monad m, Foldable g)
145− => [ElemMatcher]
136+ => [NameMatcher]
146 -> DomParserT [] m a
137 -> DomParserT [] m a
147 -> DomParserT g m a
138 -> DomParserT g m a
148divePath path = magnify $ to modElems
139divePath path = magnify $ to modElems
151 = over pdElements (toListOf $ folded . diver)
142 = over pdElements (toListOf $ folded . diver)
152− . over pdPath (<> DomPath (L.map _emShow path))
143+ . over pdPath (<> DomPath (L.map _nmShow path))
153 diver :: Fold Element Element
144 diver :: Fold Element Element
154 diver = F.foldr (.) id $ L.map toDive path
145 diver = F.foldr (.) id $ L.map toDive path
155− toDive n = nodes . folded . _Element . elMatch n
146+ toDive n = nodes . folded . _Element . elMatchName n
158 :: (Monad m, Foldable g)
149 :: (Monad m, Foldable g)
159− => ElemMatcher
150+ => NameMatcher
160 -> DomParserT [] m a
151 -> DomParserT [] m a
161 -> DomParserT g m a
152 -> DomParserT g m a
162diveElem p = divePath [p]
153diveElem p = divePath [p]
@@ -197,6 +188,6 @@ ignoreBlank = ignoreElem test
198 elems = e ^.. nodes . folded . _Element
189 elems = e ^.. nodes . folded . _Element
199 cont = mconcat $ e ^.. nodes . folded . _Content
190 cont = mconcat $ e ^.. nodes . folded . _Content
200− in if | not $ L.null elems -> False
191+ in if | not $ L.null elems -> False
201 | T.null $ T.strip cont -> True
192 | T.null $ T.strip cont -> True
202 | otherwise -> False
193 | otherwise -> False