@@ -1,107 +1,76 @@
1−{-# LANGUAGE Rank2Types, FlexibleContexts #-}
1+{-# LANGUAGE Rank2Types #-}
2−{-# OPTIONS_GHC -fno-warn-orphans #-}
3-----------------------------------------------------------------------------
2-----------------------------------------------------------------------------
5-- Module : Text.XML.Lens
4-- Module : Text.XML.Lens
6−-- Copyright : (C) 2015 Fumiaki Kinoshita
5+-- Copyright : (C) 2013 Fumiaki Kinoshita
7-- License : BSD-style (see the file LICENSE)
6-- License : BSD-style (see the file LICENSE)
9-- Maintainer : Fumiaki Kinoshita <fumiexcel@gmail.com>
8-- Maintainer : Fumiaki Kinoshita <fumiexcel@gmail.com>
10−-- Stability : provisional
9+-- Stability : experimental
11-- Portability : non-portable
10-- Portability : non-portable
13----------------------------------------------------------------------------
12----------------------------------------------------------------------------
14module Text.XML.Lens (
13module Text.XML.Lens (
15− -- * Lenses, traversals for 'Element'
14+ -- * Useful traversals inspired by XPath
25 , attributeIs
17 , attributeIs
26 , attributeSatisfies
18 , attributeSatisfies
27− , attributeSatisfies'
35− -- ** Children
21+ -- * Lenses, traversals for 'Element'
37 -- * Prisms for 'Node'
27 -- * Prisms for 'Node'
39 , _Element
28 , _Element
40 , _Content
29 , _Content
41 , AsInstruction(..)
30 , AsInstruction(..)
42 , AsComment(..)
31 , AsComment(..)
43 -- * Lenses for 'Document'
32 -- * Lenses for 'Document'
46 , prologue
34 , prologue
47 , epilogue
35 , epilogue
49 -- * Lenses for 'Name'
37 -- * Lenses for 'Name'
51 , _nameLocalName
38 , _nameLocalName
52 , _nameNamespace
39 , _nameNamespace
53 , _namePrefix
40 , _namePrefix
54− -- * Lenses for 'Instruction'
59import Text.XML
42import Text.XML
60import Control.Lens
43import Control.Lens
61import Data.Text (Text)
44import Data.Text (Text)
62import Data.Map (Map)
45import Data.Map (Map)
63−import qualified Data.CaseInsensitive as CI
46+import Control.Applicative
64−import Data.Maybe (isNothing)
47+
66prologue :: Lens' Document Prologue
50prologue :: Lens' Document Prologue
67prologue f doc = fmap (\p -> doc { documentPrologue = p} ) $ f $ documentPrologue doc
51prologue f doc = fmap (\p -> doc { documentPrologue = p} ) $ f $ documentPrologue doc
68−{-# INLINE prologue #-}
70−-- | The root element of the document.
71root :: Lens' Document Element
53root :: Lens' Document Element
72root f doc = fmap (\p -> doc { documentRoot = p} ) $ f $ documentRoot doc
54root f doc = fmap (\p -> doc { documentRoot = p} ) $ f $ documentRoot doc
75epilogue :: Lens' Document [Miscellaneous]
56epilogue :: Lens' Document [Miscellaneous]
76epilogue f doc = fmap (\p -> doc { documentEpilogue = p} ) $ f $ documentEpilogue doc
57epilogue f doc = fmap (\p -> doc { documentEpilogue = p} ) $ f $ documentEpilogue doc
77−{-# INLINE epilogue #-}
79doctype :: Lens' Prologue (Maybe Doctype)
59doctype :: Lens' Prologue (Maybe Doctype)
80doctype f doc = fmap (\p -> doc { prologueDoctype = p} ) $ f $ prologueDoctype doc
60doctype f doc = fmap (\p -> doc { prologueDoctype = p} ) $ f $ prologueDoctype doc
81−{-# INLINE doctype #-}
83class AsInstruction t where
62class AsInstruction t where
84 _Instruction :: Prism' t Instruction
63 _Instruction :: Prism' t Instruction
86−_instructionTarget :: Lens' Instruction Text
87−_instructionTarget f (Instruction t d) = f t <&> \t' -> Instruction t' d
88−{-# INLINE _instructionTarget #-}
90−_instructionData :: Lens' Instruction Text
91−_instructionData f (Instruction t d) = f d <&> \d' -> Instruction t d'
92−{-# INLINE _instructionData #-}
94instance AsInstruction Node where
65instance AsInstruction Node where
95 _Instruction = prism' NodeInstruction $ \s -> case s of
66 _Instruction = prism' NodeInstruction $ \s -> case s of
96 NodeInstruction e -> Just e
67 NodeInstruction e -> Just e
97 _ -> Nothing
68 _ -> Nothing
98− {-# INLINE _Instruction #-}
100instance AsInstruction Miscellaneous where
70instance AsInstruction Miscellaneous where
101 _Instruction = prism' MiscInstruction $ \s -> case s of
71 _Instruction = prism' MiscInstruction $ \s -> case s of
102 MiscInstruction e -> Just e
72 MiscInstruction e -> Just e
103 _ -> Nothing
73 _ -> Nothing
104− {-# INLINE _Instruction #-}
106class AsComment t where
75class AsComment t where
107 _Comment :: Prism' t Text
76 _Comment :: Prism' t Text
@@ -110,107 +79,65 @@ instance AsComment Node where
110 _Comment = prism' NodeComment $ \s -> case s of
79 _Comment = prism' NodeComment $ \s -> case s of
111 NodeComment e -> Just e
80 NodeComment e -> Just e
112 _ -> Nothing
81 _ -> Nothing
113− {-# INLINE _Comment #-}
115instance AsComment Miscellaneous where
83instance AsComment Miscellaneous where
116 _Comment = prism' MiscComment $ \s -> case s of
84 _Comment = prism' MiscComment $ \s -> case s of
117 MiscComment e -> Just e
85 MiscComment e -> Just e
118 _ -> Nothing
86 _ -> Nothing
119− {-# INLINE _Comment #-}
121_nameLocalName :: Lens' Name Text
88_nameLocalName :: Lens' Name Text
122−_nameLocalName f n = f (nameLocalName n) <&> \x -> n { nameLocalName = x }
89+_nameLocalName f n = fmap (\x -> n { nameLocalName = x }) $ f $ nameLocalName n
123−{-# INLINE _nameLocalName #-}
125_nameNamespace :: Lens' Name (Maybe Text)
91_nameNamespace :: Lens' Name (Maybe Text)
126−_nameNamespace f n = f (nameNamespace n) <&> \x -> n { nameNamespace = x }
92+_nameNamespace f n = fmap (\x -> n { nameNamespace = x }) $ f $ nameNamespace n
127−{-# INLINE _nameNamespace #-}
129_namePrefix :: Lens' Name (Maybe Text)
94_namePrefix :: Lens' Name (Maybe Text)
130−_namePrefix f n = f (namePrefix n) <&> \x -> n { namePrefix = x }
95+_namePrefix f n = fmap (\x -> n { namePrefix = x }) $ f $ namePrefix n
131−{-# INLINE _namePrefix #-}
133_Element :: Prism' Node Element
97_Element :: Prism' Node Element
134_Element = prism' NodeElement $ \s -> case s of
98_Element = prism' NodeElement $ \s -> case s of
135 NodeElement e -> Just e
99 NodeElement e -> Just e
136 _ -> Nothing
100 _ -> Nothing
137−{-# INLINE _Element #-}
139_Content :: Prism' Node Text
102_Content :: Prism' Node Text
140_Content = prism' NodeContent $ \s -> case s of
103_Content = prism' NodeContent $ \s -> case s of
141 NodeContent e -> Just e
104 NodeContent e -> Just e
142 _ -> Nothing
105 _ -> Nothing
143−{-# INLINE _Content #-}
145name :: Lens' Element Name
107name :: Lens' Element Name
146−name f e = f (elementName e) <&> \x -> e { elementName = x }
108+name f e = fmap (\x -> e { elementName = x }) $ f $ elementName e
149−localName :: Lens' Element Text
150−localName = name . _nameLocalName
151−{-# INLINE localName #-}
153attrs :: Lens' Element (Map Name Text)
110attrs :: Lens' Element (Map Name Text)
154attrs f e = fmap (\x -> e { elementAttributes = x }) $ f $ elementAttributes e
111attrs f e = fmap (\x -> e { elementAttributes = x }) $ f $ elementAttributes e
157nodes :: Lens' Element [Node]
113nodes :: Lens' Element [Node]
158nodes f e = fmap (\x -> e { elementNodes = x }) $ f $ elementNodes e
114nodes f e = fmap (\x -> e { elementNodes = x }) $ f $ elementNodes e
161attr :: Name -> Traversal' Element Text
116attr :: Name -> Traversal' Element Text
162attr n = attrs . ix n
117attr n = attrs . ix n
165attribute :: Name -> Lens' Element (Maybe Text)
119attribute :: Name -> Lens' Element (Maybe Text)
166attribute n = attrs . at n
120attribute n = attrs . at n
167−{-# INLINE attribute #-}
169−-- | Traverse elements which has the specified *local* name (case-insensitive).
170−named :: CI.CI Text -> Traversal' Element Element
172− | CI.mk (nameLocalName (elementName s)) == n = f s
173− | otherwise = pure s
176−-- | Old name for 'named'
177−ell :: Text -> Traversal' Element Element
178−ell n = named $ CI.mk n
180−-- | Traverse elements which has the specified name.
181el :: Name -> Traversal' Element Element
122el :: Name -> Traversal' Element Element
183 | elementName s == n = f s
124 | elementName s == n = f s
184 | otherwise = pure s
125 | otherwise = pure s
185−{-# DEPRECATED el "Use named instead" #-}
187attributeSatisfies :: Name -> (Text -> Bool) -> Traversal' Element Element
127attributeSatisfies :: Name -> (Text -> Bool) -> Traversal' Element Element
188−attributeSatisfies n p = attributeSatisfies' n (maybe False p)
128+attributeSatisfies n p = plate . filtered (maybe False p . preview (attrs . ix n))
189−{-# INLINE attributeSatisfies #-}
191−attributeSatisfies' :: Name -> (Maybe Text -> Bool) -> Traversal' Element Element
192−attributeSatisfies' n p = filtered (p . preview (attrs . ix n))
193−{-# INLINE attributeSatisfies' #-}
195−withoutAttribute :: Name -> Traversal' Element Element
196−withoutAttribute n = attributeSatisfies' n isNothing
197−{-# INLINE withoutAttribute #-}
199attributeIs :: Name -> Text -> Traversal' Element Element
130attributeIs :: Name -> Text -> Traversal' Element Element
200attributeIs n v = attributeSatisfies n (==v)
131attributeIs n v = attributeSatisfies n (==v)
201−{-# INLINE attributeIs #-}
203−-- | Traverse all contents of the element.
204text :: Traversal' Element Text
133text :: Traversal' Element Text
205text = nodes . traverse . _Content
134text = nodes . traverse . _Content
208−-- | Traverse all comments of the element.
209comment :: Traversal' Element Text
136comment :: Traversal' Element Text
210comment = nodes . traverse . _Comment
137comment = nodes . traverse . _Comment
211−{-# INLINE comment #-}
213−-- | 'plate' traverses over its sub-elements.
214instance Plated Element where
139instance Plated Element where
215 plate = nodes . traverse . _Element
140 plate = nodes . traverse . _Element
142+(./) :: Plated a => Traversal s t a a -> Traversal a a u v -> Traversal s t u v
216− {-# INLINE plate #-}
143+l ./ m = l . plate . m