@@ -14,7 +14,7 @@
1414module Text.XML.Lens (
1515 -- * Lenses, traversals for 'Element'
1616 Element(..)
17− , (...)
17+ , (./)
1818 -- ** Names
1919 , name
2020 , localName
@@ -24,8 +24,6 @@ module Text.XML.Lens (
2424 -- ** Attributes
2525 , attributeIs
2626 , attributeSatisfies
27− , attributeSatisfies'
28− , withoutAttribute
2927 , attr
3028 , attribute
3129 , attrs
@@ -33,6 +31,7 @@ module Text.XML.Lens (
3331 , text
3432 , comment
3533 -- ** Children
34+ , entire
3635 , nodes
3736 -- * Prisms for 'Node'
3837 , Node(..)
@@ -55,53 +54,49 @@ module Text.XML.Lens (
5554 , Instruction(..)
5655 , _instructionTarget
5756 , _instructionData
57+ -- * Reexport
58+ , module Control.Lens
5859 ) where
5960import Text.XML
6061import Control.Lens
6162import Data.Text (Text)
6263import Data.Map (Map)
64+import Control.Applicative
6365import qualified Data.CaseInsensitive as CI
64−import Data.Maybe (isNothing)
66+
67+infixr 9 ./
6568
6669prologue :: Lens' Document Prologue
6770prologue f doc = fmap (\p -> doc { documentPrologue = p} ) $ f $ documentPrologue doc
68−{-# INLINE prologue #-}
6971
7072-- | The root element of the document.
7173root :: Lens' Document Element
7274root f doc = fmap (\p -> doc { documentRoot = p} ) $ f $ documentRoot doc
73−{-# INLINE root #-}
7475
7576epilogue :: Lens' Document [Miscellaneous]
7677epilogue f doc = fmap (\p -> doc { documentEpilogue = p} ) $ f $ documentEpilogue doc
77−{-# INLINE epilogue #-}
7878
7979doctype :: Lens' Prologue (Maybe Doctype)
8080doctype f doc = fmap (\p -> doc { prologueDoctype = p} ) $ f $ prologueDoctype doc
81−{-# INLINE doctype #-}
8281
8382class AsInstruction t where
8483 _Instruction :: Prism' t Instruction
8584
8685_instructionTarget :: Lens' Instruction Text
8786_instructionTarget f (Instruction t d) = f t <&> \t' -> Instruction t' d
88−{-# INLINE _instructionTarget #-}
8987
9088_instructionData :: Lens' Instruction Text
9189_instructionData f (Instruction t d) = f d <&> \d' -> Instruction t d'
92−{-# INLINE _instructionData #-}
9390
9491instance AsInstruction Node where
9592 _Instruction = prism' NodeInstruction $ \s -> case s of
9693 NodeInstruction e -> Just e
9794 _ -> Nothing
98− {-# INLINE _Instruction #-}
9995
10096instance AsInstruction Miscellaneous where
10197 _Instruction = prism' MiscInstruction $ \s -> case s of
10298 MiscInstruction e -> Just e
10399 _ -> Nothing
104− {-# INLINE _Instruction #-}
105100
106101class AsComment t where
107102 _Comment :: Prism' t Text
@@ -110,41 +105,33 @@ instance AsComment Node where
110105 _Comment = prism' NodeComment $ \s -> case s of
111106 NodeComment e -> Just e
112107 _ -> Nothing
113− {-# INLINE _Comment #-}
114108
115109instance AsComment Miscellaneous where
116110 _Comment = prism' MiscComment $ \s -> case s of
117111 MiscComment e -> Just e
118112 _ -> Nothing
119− {-# INLINE _Comment #-}
120113
121114_nameLocalName :: Lens' Name Text
122115_nameLocalName f n = f (nameLocalName n) <&> \x -> n { nameLocalName = x }
123−{-# INLINE _nameLocalName #-}
124116
125117_nameNamespace :: Lens' Name (Maybe Text)
126118_nameNamespace f n = f (nameNamespace n) <&> \x -> n { nameNamespace = x }
127−{-# INLINE _nameNamespace #-}
128119
129120_namePrefix :: Lens' Name (Maybe Text)
130121_namePrefix f n = f (namePrefix n) <&> \x -> n { namePrefix = x }
131−{-# INLINE _namePrefix #-}
132122
133123_Element :: Prism' Node Element
134124_Element = prism' NodeElement $ \s -> case s of
135125 NodeElement e -> Just e
136126 _ -> Nothing
137−{-# INLINE _Element #-}
138127
139128_Content :: Prism' Node Text
140129_Content = prism' NodeContent $ \s -> case s of
141130 NodeContent e -> Just e
142131 _ -> Nothing
143−{-# INLINE _Content #-}
144132
145133name :: Lens' Element Name
146134name f e = f (elementName e) <&> \x -> e { elementName = x }
147−{-# INLINE name #-}
148135
149136localName :: Lens' Element Text
150137localName = name . _nameLocalName
@@ -152,65 +139,60 @@ localName = name . _nameLocalName
152139
153140attrs :: Lens' Element (Map Name Text)
154141attrs f e = fmap (\x -> e { elementAttributes = x }) $ f $ elementAttributes e
155−{-# INLINE attrs #-}
156142
157143nodes :: Lens' Element [Node]
158144nodes f e = fmap (\x -> e { elementNodes = x }) $ f $ elementNodes e
159−{-# INLINE nodes #-}
160145
161146attr :: Name -> Traversal' Element Text
162147attr n = attrs . ix n
163−{-# INLINE attr #-}
164148
165149attribute :: Name -> Lens' Element (Maybe Text)
166150attribute n = attrs . at n
167−{-# INLINE attribute #-}
151+
152+-- | Traverse itself with its all children. Rewriting subnodes of each children will break a traversal law.
153+entire :: Traversal' Element Element
154+entire f e@(Element _ _ ns) = com <$> f e <*> traverse (_Element (entire f)) ns where
155+ com (Element n a _) = Element n a
168156
169157-- | Traverse elements which has the specified *local* name (case-insensitive).
170158named :: CI.CI Text -> Traversal' Element Element
171159named n f s
172160 | CI.mk (nameLocalName (elementName s)) == n = f s
173161 | otherwise = pure s
174−{-# INLINE named #-}
175162
176163-- | Old name for 'named'
177164ell :: Text -> Traversal' Element Element
178−ell n = named $ CI.mk n
165+ell = named . CI.mk
179166
180167-- | Traverse elements which has the specified name.
181168el :: Name -> Traversal' Element Element
182169el n f s
183170 | elementName s == n = f s
184171 | otherwise = pure s
185−{-# DEPRECATED el "Use named instead" #-}
186172
187173attributeSatisfies :: Name -> (Text -> Bool) -> Traversal' Element Element
188−attributeSatisfies n p = attributeSatisfies' n (maybe False p)
189−{-# INLINE attributeSatisfies #-}
190−
191−attributeSatisfies' :: Name -> (Maybe Text -> Bool) -> Traversal' Element Element
192−attributeSatisfies' n p = filtered (p . preview (attrs . ix n))
193−{-# INLINE attributeSatisfies' #-}
194−
195−withoutAttribute :: Name -> Traversal' Element Element
196−withoutAttribute n = attributeSatisfies' n isNothing
197−{-# INLINE withoutAttribute #-}
174+attributeSatisfies n p = filtered (maybe False p . preview (attrs . ix n))
198175
199176attributeIs :: Name -> Text -> Traversal' Element Element
200177attributeIs n v = attributeSatisfies n (==v)
201−{-# INLINE attributeIs #-}
202178
203179-- | Traverse all contents of the element.
204180text :: Traversal' Element Text
205181text = nodes . traverse . _Content
206−{-# INLINE text #-}
207182
208183-- | Traverse all comments of the element.
209184comment :: Traversal' Element Text
210185comment = nodes . traverse . _Comment
211−{-# INLINE comment #-}
212186
213187-- | 'plate' traverses over its sub-elements.
214188instance Plated Element where
215189 plate = nodes . traverse . _Element
216− {-# INLINE plate #-}
190+
191+-- | Combine two 'Traversal's just like XPath's slash. Identical to ('...').
192+--
193+-- @
194+-- l ./ m ≡ l . 'plate' . m
195+-- @
196+(./) :: (Applicative f, Plated c) => LensLike f s t c c -> Over p f c c a b -> Over p f s t a b
197+(./) = (...)
198+{-# INLINE (./) #-}