git.iko.soy/typeable/xml-lens
on master help sign in
8 files changed+112−36
since splitsnapshots
unifiedsplit
.github/workflows/haskell.yml+37 .gitignore+1 CHANGELOG.md+10 README.md+8−4 Text/XML/Lens.hs+40−24 cabal.project+1 stack.yaml+4 xml-lens.cabal+11−8
.github/workflows/haskell.ymlnew file+37
@@ -0,0 +1,37 @@
1+name: Haskell CI
2+
3+on: [push, pull_request]
4+
5+jobs:
6+ build:
7+
8+ runs-on: ubuntu-latest
9+ strategy:
10+ matrix:
11+ ghc: [ '8.8.4', '8.10.7', '9.0.1', '9.2.2' ]
12+ steps:
13+ - uses: actions/checkout@v3
14+ - uses: haskell/actions/setup@v1
15+ with:
16+ ghc-version: ${{ matrix.ghc }}
17+ cabal-version: '3.4'
18+
19+ - name: cabal Cache
20+ uses: actions/cache@v1
21+ env:
22+ cache-name: cache-cabal
23+ with:
24+ path: ~/.cabal
25+ key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/*.cabal') }}-${{ hashFiles('**/cabal.project') }}
26+ restore-keys: |
27+ ${{ runner.os }}-build-${{ env.cache-name }}-
28+ ${{ runner.os }}-build-
29+ ${{ runner.os }}-
30+ - name: Install dependencies
31+ run: |
32+ cabal update
33+ cabal build --only-dependencies --enable-tests --enable-benchmarks all
34+ - name: Build
35+ run: cabal build --enable-tests --enable-benchmarks all
36+ - name: Run tests
37+ run: cabal test --enable-tests --enable-benchmarks all
.gitignore+1
@@ -1,3 +1,4 @@
1+dist-newstyle
12#################
23## Eclipse
34#################
CHANGELOG.mdnew file+10
@@ -0,0 +1,10 @@
1+## 0.3.1
2+
3+* Supported GHC 9
4+
5+## 0.3 (2021/01)
6+
7+* Deprecated `el`
8+* Removed `./` and `entire`
9+
10+
README.md+8−4
@@ -9,16 +9,16 @@ Example
99```haskell
1010> doc <- Text.XML.readFile def "examples/books.xml"
1111
12−> doc ^.. root . el "books" ./ el "book" . attributeIs "category" "Textbooks" ./ el "title" . text
12+> doc ^.. root . named "books" ... named "book" . attributeIs "category" "Textbooks" ... named "title" . text
1313["Learn You a Haskell for Great Good!","Programming in Haskell","Real World Haskell"]
1414
15−> lengthOf ?? doc $ root . el "books" ./ el "book"
15+> lengthOf ?? doc $ root . named "books" ... named "book"
16167
1717
18−> doc ^? root . el "books" ./ attributeIs "category" "Joke" ./ el "title" . text
18+> doc ^? root . named "books" ... attributeIs "category" "Joke" ... named "title" . text
1919Just "Functional Ikamusume"
2020
21−> doc & root . el "books" ./ el "book" ./ el "pages" . text <>~ " pages" & renderLBS def & BL.putStrLn
21+> doc & root . named "books" ... named "book" ... named "pages" . text <>~ " pages" & renderLBS def & BL.putStrLn
2222```
2323
2424```xml
@@ -43,4 +43,8 @@ Just "Functional Ikamusume"
4343…
4444```
4545
46+Tips
47+----
4648
49+* Use [cosmos](http://hackage.haskell.org/package/lens-4.19.2/docs/Control-Lens-Plated.html) to traverse over all children
50+* You can do or-composition of traversals with [failing](http://hackage.haskell.org/package/lens-4.19.2/docs/Control-Lens-Traversal.html#v:failing)
Text/XML/Lens.hs+40−24
@@ -14,7 +14,6 @@
1414module Text.XML.Lens (
1515 -- * Lenses, traversals for 'Element'
1616 Element(..)
17− , (./)
1817 , (...)
1918 -- ** Names
2019 , name
@@ -25,6 +24,8 @@ module Text.XML.Lens (
2524 -- ** Attributes
2625 , attributeIs
2726 , attributeSatisfies
27+ , attributeSatisfies'
28+ , withoutAttribute
2829 , attr
2930 , attribute
3031 , attrs
@@ -32,7 +33,6 @@ module Text.XML.Lens (
3233 , text
3334 , comment
3435 -- ** Children
35− , entire
3636 , nodes
3737 -- * Prisms for 'Node'
3838 , Node(..)
@@ -60,42 +60,48 @@ import Text.XML
6060import Control.Lens
6161import Data.Text (Text)
6262import Data.Map (Map)
63−import Control.Applicative
6463import qualified Data.CaseInsensitive as CI
65−
66−infixr 9 ./
64+import Data.Maybe (isNothing)
6765
6866prologue :: Lens' Document Prologue
6967prologue f doc = fmap (\p -> doc { documentPrologue = p} ) $ f $ documentPrologue doc
68+{-# INLINE prologue #-}
7069
7170-- | The root element of the document.
7271root :: Lens' Document Element
7372root f doc = fmap (\p -> doc { documentRoot = p} ) $ f $ documentRoot doc
73+{-# INLINE root #-}
7474
7575epilogue :: Lens' Document [Miscellaneous]
7676epilogue f doc = fmap (\p -> doc { documentEpilogue = p} ) $ f $ documentEpilogue doc
77+{-# INLINE epilogue #-}
7778
7879doctype :: Lens' Prologue (Maybe Doctype)
7980doctype f doc = fmap (\p -> doc { prologueDoctype = p} ) $ f $ prologueDoctype doc
81+{-# INLINE doctype #-}
8082
8183class AsInstruction t where
8284 _Instruction :: Prism' t Instruction
8385
8486_instructionTarget :: Lens' Instruction Text
8587_instructionTarget f (Instruction t d) = f t <&> \t' -> Instruction t' d
88+{-# INLINE _instructionTarget #-}
8689
8790_instructionData :: Lens' Instruction Text
8891_instructionData f (Instruction t d) = f d <&> \d' -> Instruction t d'
92+{-# INLINE _instructionData #-}
8993
9094instance AsInstruction Node where
9195 _Instruction = prism' NodeInstruction $ \s -> case s of
9296 NodeInstruction e -> Just e
9397 _ -> Nothing
98+ {-# INLINE _Instruction #-}
9499
95100instance AsInstruction Miscellaneous where
96101 _Instruction = prism' MiscInstruction $ \s -> case s of
97102 MiscInstruction e -> Just e
98103 _ -> Nothing
104+ {-# INLINE _Instruction #-}
99105
100106class AsComment t where
101107 _Comment :: Prism' t Text
@@ -104,33 +110,41 @@ instance AsComment Node where
104110 _Comment = prism' NodeComment $ \s -> case s of
105111 NodeComment e -> Just e
106112 _ -> Nothing
113+ {-# INLINE _Comment #-}
107114
108115instance AsComment Miscellaneous where
109116 _Comment = prism' MiscComment $ \s -> case s of
110117 MiscComment e -> Just e
111118 _ -> Nothing
119+ {-# INLINE _Comment #-}
112120
113121_nameLocalName :: Lens' Name Text
114122_nameLocalName f n = f (nameLocalName n) <&> \x -> n { nameLocalName = x }
123+{-# INLINE _nameLocalName #-}
115124
116125_nameNamespace :: Lens' Name (Maybe Text)
117126_nameNamespace f n = f (nameNamespace n) <&> \x -> n { nameNamespace = x }
127+{-# INLINE _nameNamespace #-}
118128
119129_namePrefix :: Lens' Name (Maybe Text)
120130_namePrefix f n = f (namePrefix n) <&> \x -> n { namePrefix = x }
131+{-# INLINE _namePrefix #-}
121132
122133_Element :: Prism' Node Element
123134_Element = prism' NodeElement $ \s -> case s of
124135 NodeElement e -> Just e
125136 _ -> Nothing
137+{-# INLINE _Element #-}
126138
127139_Content :: Prism' Node Text
128140_Content = prism' NodeContent $ \s -> case s of
129141 NodeContent e -> Just e
130142 _ -> Nothing
143+{-# INLINE _Content #-}
131144
132145name :: Lens' Element Name
133146name f e = f (elementName e) <&> \x -> e { elementName = x }
147+{-# INLINE name #-}
134148
135149localName :: Lens' Element Text
136150localName = name . _nameLocalName
@@ -138,63 +152,65 @@ localName = name . _nameLocalName
138152
139153attrs :: Lens' Element (Map Name Text)
140154attrs f e = fmap (\x -> e { elementAttributes = x }) $ f $ elementAttributes e
155+{-# INLINE attrs #-}
141156
142157nodes :: Lens' Element [Node]
143158nodes f e = fmap (\x -> e { elementNodes = x }) $ f $ elementNodes e
159+{-# INLINE nodes #-}
144160
145161attr :: Name -> Traversal' Element Text
146162attr n = attrs . ix n
163+{-# INLINE attr #-}
147164
148165attribute :: Name -> Lens' Element (Maybe Text)
149166attribute n = attrs . at n
150−
151−-- | Traverse itself with its all children. Rewriting subnodes of each children will break a traversal law.
152−entire :: Traversal' Element Element
153−entire f e@(Element _ _ ns) = com <$> f e <*> traverse (_Element (entire f)) ns where
154− com (Element n a _) = Element n a
155−{-# DEPRECATED entire "Use cosmos or deep instead" #-}
167+{-# INLINE attribute #-}
156168
157169-- | Traverse elements which has the specified *local* name (case-insensitive).
158170named :: CI.CI Text -> Traversal' Element Element
159171named n f s
160172 | CI.mk (nameLocalName (elementName s)) == n = f s
161173 | otherwise = pure s
174+{-# INLINE named #-}
162175
163176-- | Old name for 'named'
164177ell :: Text -> Traversal' Element Element
165−ell = named . CI.mk
178+ell n = named $ CI.mk n
166179
167180-- | Traverse elements which has the specified name.
168181el :: Name -> Traversal' Element Element
169182el n f s
170183 | elementName s == n = f s
171184 | otherwise = pure s
185+{-# DEPRECATED el "Use named instead" #-}
172186
173187attributeSatisfies :: Name -> (Text -> Bool) -> Traversal' Element Element
174−attributeSatisfies n p = filtered (maybe False p . preview (attrs . ix n))
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 #-}
175198
176199attributeIs :: Name -> Text -> Traversal' Element Element
177200attributeIs n v = attributeSatisfies n (==v)
201+{-# INLINE attributeIs #-}
178202
179203-- | Traverse all contents of the element.
180204text :: Traversal' Element Text
181205text = nodes . traverse . _Content
206+{-# INLINE text #-}
182207
183208-- | Traverse all comments of the element.
184209comment :: Traversal' Element Text
185210comment = nodes . traverse . _Comment
211+{-# INLINE comment #-}
186212
187213-- | 'plate' traverses over its sub-elements.
188214instance Plated Element where
189215 plate = nodes . traverse . _Element
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 (./) #-}
199−
200−{-# DEPRECATED (./) "Use (...) instead" #-}
216+ {-# INLINE plate #-}
cabal.projectnew file+1
@@ -0,0 +1 @@
1+packages: ./
stack.yamlnew file+4
@@ -0,0 +1,4 @@
1+resolver: lts-21.3
2+
3+packages:
4+- .
xml-lens.cabal+11−8
@@ -1,17 +1,20 @@
1+cabal-version: 2.4
12name: xml-lens
2−version: 0.2
3+version: 0.3.1
34synopsis: Lenses, traversals, and prisms for xml-conduit
4−description: Lens-based DOM selector
5+description: This package provides DOM selectors based on lenses and prisms. See README.md for examples
56homepage: https://github.com/fumieval/xml-lens
67bug-reports: https://github.com/fumieval/xml-lens/issues
7−license: BSD3
8+license: BSD-3-Clause
89license-file: LICENSE
910author: Fumiaki Kinoshita
1011maintainer: Fumiaki Kinoshita <fumiexcel@gmail.com>
11−copyright: Copyright (C) 2019 Fumiaki Kinoshita
12+copyright: Copyright (C) 2021 Fumiaki Kinoshita
1213category: XML
1314build-type: Simple
14−cabal-version: >=1.10
15+extra-source-files:
16+ README.md
17+ CHANGELOG.md
1518
1619source-repository head
1720 type: git
@@ -22,8 +25,8 @@ library
2225 ghc-options: -Wall
2326 exposed-modules: Text.XML.Lens
2427 build-depends: base ==4.*
25− , lens >= 4.0 && < 5
28+ , lens >= 4.0 && < 5.4
2629 , containers >= 0.4.0 && < 0.7
27− , text >= 0.7 && <2
28− , xml-conduit >= 1.1 && < 1.9
30+ , text >= 0.7 && < 1.3 || >= 2 && < 2.2
31+ , xml-conduit >= 1.1 && < 1.10
2932 , case-insensitive