@@ -1,4 +1,4 @@
1−{-# LANGUAGE Rank2Types #-}
1+{-# LANGUAGE Rank2Types, FlexibleContexts #-}
2-----------------------------------------------------------------------------
2-----------------------------------------------------------------------------
4-- Module : Text.XML.Lens
4-- Module : Text.XML.Lens
@@ -8,22 +8,26 @@
8-- Maintainer : Fumiaki Kinoshita <fumiexcel@gmail.com>
8-- Maintainer : Fumiaki Kinoshita <fumiexcel@gmail.com>
9-- Stability : experimental
9-- Stability : experimental
10-- Portability : non-portable
10-- Portability : non-portable
11−--
11+-- Useful traversals inspired by XPath
12----------------------------------------------------------------------------
12----------------------------------------------------------------------------
13module Text.XML.Lens (
13module Text.XML.Lens (
14− -- * Useful traversals inspired by XPath
14+ -- * Lenses, traversals for 'Element'
17 , attributeIs
20 , attributeIs
18 , attributeSatisfies
21 , attributeSatisfies
21− -- * Lenses, traversals for 'Element'
28+ -- ** Children
27 -- * Prisms for 'Node'
31 -- * Prisms for 'Node'
28 , _Element
32 , _Element
29 , _Content
33 , _Content
@@ -38,6 +42,9 @@ module Text.XML.Lens (
38 , _nameLocalName
42 , _nameLocalName
39 , _nameNamespace
43 , _nameNamespace
40 , _namePrefix
44 , _namePrefix
45+ -- * Lenses for 'Instruction'
42import Text.XML
49import Text.XML
43import Control.Lens
50import Control.Lens
@@ -50,6 +57,7 @@ infixr 9 ./
50prologue :: Lens' Document Prologue
57prologue :: Lens' Document Prologue
51prologue f doc = fmap (\p -> doc { documentPrologue = p} ) $ f $ documentPrologue doc
58prologue f doc = fmap (\p -> doc { documentPrologue = p} ) $ f $ documentPrologue doc
60+-- | The root element of the document.
53root :: Lens' Document Element
61root :: Lens' Document Element
54root f doc = fmap (\p -> doc { documentRoot = p} ) $ f $ documentRoot doc
62root f doc = fmap (\p -> doc { documentRoot = p} ) $ f $ documentRoot doc
@@ -62,6 +70,12 @@ doctype f doc = fmap (\p -> doc { prologueDoctype = p} ) $ f $ prologueDoctype d
62class AsInstruction t where
70class AsInstruction t where
63 _Instruction :: Prism' t Instruction
71 _Instruction :: Prism' t Instruction
73+_instructionTarget :: Lens' Instruction Text
74+_instructionTarget f (Instruction t d) = f t <&> \t' -> Instruction t' d
76+_instructionData :: Lens' Instruction Text
77+_instructionData f (Instruction t d) = f d <&> \d' -> Instruction t d'
65instance AsInstruction Node where
79instance AsInstruction Node where
66 _Instruction = prism' NodeInstruction $ \s -> case s of
80 _Instruction = prism' NodeInstruction $ \s -> case s of
67 NodeInstruction e -> Just e
81 NodeInstruction e -> Just e
@@ -113,12 +127,18 @@ attrs f e = fmap (\x -> e { elementAttributes = x }) $ f $ elementAttributes e
113nodes :: Lens' Element [Node]
127nodes :: Lens' Element [Node]
114nodes f e = fmap (\x -> e { elementNodes = x }) $ f $ elementNodes e
128nodes f e = fmap (\x -> e { elementNodes = x }) $ f $ elementNodes e
116−attr :: Name -> Traversal' Element Text
130+attr :: Name -> IndexedTraversal' Name Element Text
117attr n = attrs . ix n
131attr n = attrs . ix n
119−attribute :: Name -> Lens' Element (Maybe Text)
133+attribute :: Name -> IndexedLens' Name Element (Maybe Text)
120attribute n = attrs . at n
134attribute n = attrs . at n
136+-- | Traverse itself with its all children.
137+entire :: Traversal' Element Element
138+entire f e@(Element _ _ ns) = com <$> f e <*> traverse (_Element (entire f)) ns where
139+ com (Element n a _) ns = Element n a ns
141+-- | Traverse elements which has the specified name.
122el :: Name -> Traversal' Element Element
142el :: Name -> Traversal' Element Element
124 | elementName s == n = f s
144 | elementName s == n = f s
@@ -130,14 +150,21 @@ attributeSatisfies n p = filtered (maybe False p . preview (attrs . ix n))
130attributeIs :: Name -> Text -> Traversal' Element Element
150attributeIs :: Name -> Text -> Traversal' Element Element
131attributeIs n v = attributeSatisfies n (==v)
151attributeIs n v = attributeSatisfies n (==v)
153+-- | Traverse all contents of the element.
133text :: Traversal' Element Text
154text :: Traversal' Element Text
134text = nodes . traverse . _Content
155text = nodes . traverse . _Content
157+-- | Traverse all comments of the element.
136comment :: Traversal' Element Text
158comment :: Traversal' Element Text
137comment = nodes . traverse . _Comment
159comment = nodes . traverse . _Comment
139instance Plated Element where
161instance Plated Element where
140 plate = nodes . traverse . _Element
162 plate = nodes . traverse . _Element
164+-- | Combine two 'Traversal's just like XPath's slash.
167+-- l ./ m ≡ l . 'plate' . m
142(./) :: Plated a => Traversal s t a a -> Traversal a a u v -> Traversal s t u v
169(./) :: Plated a => Traversal s t a a -> Traversal a a u v -> Traversal s t u v
143−l ./ m = l . plate . m
170+l ./ m = l . plate . m