git.iko.soy/typeable/dom-parser
on master help sign in
Upd: add ElemMatcher
commit7fb1685a50e2cf3195bd24234434dcf8082d98cd authorAleksey Uimanov <s9gf4ult@gmail.com> dateSun 8 Jan 2017, 03:33 (10 years ago) parent467a733
2 files changed+55−25
src/Text/XML/DOM/Parser/Combinators.hs+20−19 src/Text/XML/DOM/Parser/Types.hs+35−6
src/Text/XML/DOM/Parser/Combinators.hs+20−19
@@ -31,15 +31,15 @@ import Text.XML.DOM.Parser.Types
3131import Text.XML.Lens
3232
3333
34−-- | Generic function to traverse arbitrary inner cursors.
34+-- | Generic function to traverse arbitrary inner elements.
3535traverseElems
3636 :: (Monad m, Foldable g, Traversable f)
3737 => ([Element] -> DomParserT g m (f (DomPath, Element)))
3838 -- ^ Takes list of current elements and returns container with
39− -- pairs of subpath (relatively to current element) and element
39+ -- pairs of subpath (relatively to current elements) and element
4040 -- to run parser in
4141 -> DomParserT Identity m a
42− -- ^ Parser will be runned for each element found in traversable
42+ -- ^ Parser to run for each element found in traversable 'f'
4343 -> DomParserT g m (f a)
4444traverseElems trav parser = do
4545 pd <- ask
@@ -49,15 +49,15 @@ traverseElems trav parser = do
4949 newpd = ParserData
5050 { _pdElements = Identity e
5151 , _pdPath = pd ^. pdPath <> subpath }
52− -- type of reader has been changed, local won't work here
53− magnify (to $ const newpd) parser
52+ lift $ runReaderT parser newpd
5453
55−-- | Takes function filtering
54+-- | Traverses elements located in same path using filtering function
5655inFilteredTrav
5756 :: (Monad m, Foldable g, Buildable f)
5857 => ([Element] -> (DomPath, [Element]))
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.
58+ -- ^ Takes list of current elements and returns some descendants
59+ -- subset and path this descendants located at. Path is should be
60+ -- same for all descendants and required for error message
6161 -> DomParserT Identity m a
6262 -> DomParserT g m (f a)
6363inFilteredTrav deeper = traverseElems trav
@@ -70,38 +70,39 @@ inFilteredTrav deeper = traverseElems trav
7070
7171inElemTrav
7272 :: (Monad m, Foldable g, Buildable f)
73− => NameMatcher -- ^ Name of tag to traverse in
73+ => ElemMatcher -- ^ Name of tag to traverse in
7474 -> DomParserT Identity m a
7575 -> DomParserT g m (f a)
7676inElemTrav n = inFilteredTrav deeper
7777 where
78− deeper = (DomPath [_nmShow n],) . toListOf (folded . nodes . folded . _Element . elMatchName n)
78+ elemsFold = folded . nodes . folded . _Element . elMatch n
79+ deeper = (DomPath [_emShow n],) . toListOf elemsFold
7980
8081-- | Runs parser inside first children element with given name
8182inElem
8283 :: (Monad m, Foldable g)
83− => NameMatcher
84+ => ElemMatcher
8485 -> DomParserT Identity m a
8586 -> DomParserT g m a
8687inElem n = fmap runIdentity . inElemTrav n
8788
8889inElemAll
8990 :: (Monad m, Foldable g)
90− => NameMatcher
91+ => ElemMatcher
9192 -> DomParserT Identity m a
9293 -> DomParserT g m [a]
9394inElemAll = inElemTrav
9495
9596inElemMay
9697 :: (Monad m, Foldable g)
97− => NameMatcher
98+ => ElemMatcher
9899 -> DomParserT Identity m a
99100 -> DomParserT g m (Maybe a)
100101inElemMay = inElemTrav
101102
102103inElemNe
103104 :: (Monad m, Foldable g)
104− => NameMatcher
105+ => ElemMatcher
105106 -> DomParserT Identity m a
106107 -> DomParserT g m (NonEmpty a)
107108inElemNe = inElemTrav
@@ -133,21 +134,21 @@ in given path.
133134divePath
134135 :: forall m g a
135136 . (Monad m, Foldable g)
136− => [NameMatcher]
137+ => [ElemMatcher]
137138 -> DomParserT [] m a
138139 -> DomParserT g m a
139140divePath path = magnify $ to modElems
140141 where
141142 modElems
142143 = over pdElements (toListOf $ folded . diver)
143− . over pdPath (<> DomPath (L.map _nmShow path))
144+ . over pdPath (<> DomPath (L.map _emShow path))
144145 diver :: Fold Element Element
145146 diver = F.foldr (.) id $ L.map toDive path
146− toDive n = nodes . folded . _Element . elMatchName n
147+ toDive n = nodes . folded . _Element . elMatch n
147148
148149diveElem
149150 :: (Monad m, Foldable g)
150− => NameMatcher
151+ => ElemMatcher
151152 -> DomParserT [] m a
152153 -> DomParserT g m a
153154diveElem p = divePath [p]
@@ -188,6 +189,6 @@ ignoreBlank = ignoreElem test
188189 let
189190 elems = e ^.. nodes . folded . _Element
190191 cont = mconcat $ e ^.. nodes . folded . _Content
191− in if | not $ L.null elems -> False
192+ in if | not $ L.null elems -> False
192193 | T.null $ T.strip cont -> True
193194 | otherwise -> False
src/Text/XML/DOM/Parser/Types.hs+35−6
@@ -6,7 +6,12 @@ module Text.XML.DOM.Parser.Types
66 , matchName
77 , matchLocalName
88 , matchCILocalName
9− , elMatchName
9+ -- * Element matching
10+ , ElemMatcher(..)
11+ , emMatch
12+ , emShow
13+ , matchElemName
14+ , elMatch
1015 -- * Parser internals
1116 , DomPath(..)
1217 , ParserError(..)
@@ -37,6 +42,30 @@ import GHC.Generics (Generic)
3742import Text.XML
3843import Text.XML.Lens
3944
45+-- | Arbitrary element matcher
46+data ElemMatcher = ElemMatcher
47+ { _emMatch :: Element -> Bool
48+ , _emShow :: Text
49+ }
50+
51+makeLenses ''ElemMatcher
52+
53+instance IsString ElemMatcher where
54+ fromString = matchElemName . fromString
55+
56+instance Show ElemMatcher where
57+ show = T.unpack . _emShow
58+
59+-- | Match element by name
60+matchElemName :: NameMatcher -> ElemMatcher
61+matchElemName (NameMatcher matchName showName) = ElemMatcher
62+ { _emMatch = views name matchName
63+ , _emShow = showName
64+ }
65+
66+elMatch :: ElemMatcher -> Traversal' Element Element
67+elMatch (ElemMatcher match _) = filtered match
68+
4069-- | Arbitrary name matcher. Match name any way you want, but
4170-- considered to be used as comparator with some name with some rules
4271data NameMatcher = NameMatcher
@@ -81,9 +110,8 @@ matchName n = NameMatcher
81110 , _nmShow = nameLocalName n
82111 }
83112
84−elMatchName :: NameMatcher -> Traversal' Element Element
85−elMatchName nm = filtered (views name $ nm ^. nmMatch)
86−
113+-- | Path some element should be found at. Path starts from the root
114+-- element of the document. Errors are much more usefull with path.
87115newtype DomPath = DomPath
88116 { unDomPath :: [Text]
89117 } deriving (Eq, Ord, Show, Monoid)
@@ -139,8 +167,9 @@ makePrisms ''ParserErrors
139167instance Exception ParserErrors
140168
141169
142−{- | Parser scope parser runs in. Functor argument is usually @Identity@ or
143−@[]@.
170+{- | Parser scope.
171+
172+Functor argument is usually @Identity@ or @[]@.
144173
145174If functor is @Identity@ then parser expects exactly ONE current element. This
146175is common behavior for content parsers, or parsers expecting strict XML