git.iko.soy/typeable/xml-isogen
on master help sign in
Merge pull request #16 from odr/master

Add: contents in composite types

commit3336f05c19e3408d95735cdc323363a5b05d8d9f authorDenis Redozubov <denis.redozubov@gmail.com> dateTue 14 May 2019, 18:46 (7 years ago) parentc1c2f9b8a06d40
9 files changed+96−25
.travis.yml+1−1 ghc-802.yaml+1−1 ghc-822.yaml+1−1 ghc-841.yaml → ghc-844.yaml+1−1 src/Data/THGen/XML.hs+59−18 src/Text/XML/DOM/Parser/Internal/Content.hs+28 stack.yaml+1−1 test/TestDefs.hs+2−1 xml-isogen.cabal+2−1
.travis.yml+1−1
@@ -6,7 +6,7 @@ env:
66 - STACK_YAML=stack.yaml
77 - STACK_YAML=ghc-802.yaml
88 - STACK_YAML=ghc-822.yaml
9− - STACK_YAML=ghc-841.yaml
9+ - STACK_YAML=ghc-844.yaml
1010
1111cache:
1212 directories:
ghc-802.yaml+1−1
@@ -1,4 +1,4 @@
1−resolver: lts-9.0
1+resolver: lts-9.21
22
33packages:
44- .
ghc-822.yaml+1−1
@@ -1 +1 @@
1−resolver: lts-10.0
1+resolver: lts-11.22
ghc-841.yaml → ghc-844.yamlrenamed+1−1
@@ -1,3 +1,3 @@
1−resolver: nightly-2018-03-20
1+resolver: lts-12.16
22extra-deps:
33- dom-parser-3.1.0
src/Data/THGen/XML.hs+59−18
@@ -114,6 +114,7 @@ module Data.THGen.XML
114114 , (!%)
115115 , (?%)
116116 , (&)
117+ , (^)
117118 , (=:=)
118119 -- Re-exports
119120 , T.Text
@@ -133,12 +134,12 @@ import Data.THGen.Enum
133134import qualified Data.Text as T
134135import GHC.Generics (Generic)
135136import qualified Language.Haskell.TH as TH
136−import qualified Language.Haskell.TH.Syntax as TH
137−import Prelude hiding ((+), (*))
137+import Prelude hiding ((+), (*), (^))
138138import qualified Text.XML as X
139−import Text.XML.DOM.Parser
139+import Text.XML.DOM.Parser hiding (parseContent)
140140import Text.XML.ParentAttributes
141141import qualified Text.XML.Writer as XW
142+import Text.XML.DOM.Parser.Internal.Content
142143
143144
144145data XmlFieldPlural
@@ -157,13 +158,18 @@ data IsoXmlDescPreField = IsoXmlDescPreField String TH.TypeQ
157158
158159data IsoXmlDescPreAttribute = IsoXmlDescPreAttribute String TH.TypeQ
159160
161+data IsoXmlDescPreContent = IsoXmlDescPreContent String TH.TypeQ
162+
160163data IsoXmlDescField = IsoXmlDescField XmlFieldPlural String TH.TypeQ
161164
162165data IsoXmlDescAttribute = IsoXmlDescAttribute XmlAttributePlural String TH.TypeQ
163166
167+data IsoXmlDescContent = IsoXmlDescContent String TH.TypeQ
168+
164169data IsoXmlDescRecordPart
165170 = IsoXmlDescRecordField IsoXmlDescField
166171 | IsoXmlDescRecordAttribute IsoXmlDescAttribute
172+ | IsoXmlDescRecordContent IsoXmlDescContent
167173
168174newtype IsoXmlDescRecord = IsoXmlDescRecord [IsoXmlDescRecordPart]
169175
@@ -199,6 +205,14 @@ appendAttribute plural xrec (IsoXmlDescPreAttribute name ty) =
199205 let xattribute = IsoXmlDescRecordAttribute $ IsoXmlDescAttribute plural name ty
200206 in over _IsoXmlDescRecord (xattribute:) xrec
201207
208+appendContent
209+ :: IsoXmlDescRecord
210+ -> IsoXmlDescPreContent
211+ -> IsoXmlDescRecord
212+appendContent xrec (IsoXmlDescPreContent name ty) =
213+ let xcontent = IsoXmlDescRecordContent $ IsoXmlDescContent name ty
214+ in over _IsoXmlDescRecord (xcontent:) xrec
215+
202216(!), (?), (*), (+) :: IsoXmlDescRecord -> IsoXmlDescPreField -> IsoXmlDescRecord
203217(!) = appendField XmlFieldPluralMandatory
204218(?) = appendField XmlFieldPluralOptional
@@ -209,12 +223,16 @@ appendAttribute plural xrec (IsoXmlDescPreAttribute name ty) =
209223(!%) = appendAttribute XmlAttributePluralMandatory
210224(?%) = appendAttribute XmlAttributePluralOptional
211225
226+(^) :: IsoXmlDescRecord -> IsoXmlDescPreContent -> IsoXmlDescRecord
227+(^) = appendContent
228+
212229infixl 2 !
213230infixl 2 ?
214231infixl 2 *
215232infixl 2 +
216233infixl 2 !%
217234infixl 2 ?%
235+infixl 2 ^
218236
219237appendEnumCon :: IsoXmlDescEnum -> IsoXmlDescEnumCon -> IsoXmlDescEnum
220238appendEnumCon xenum xenumcon =
@@ -257,11 +275,19 @@ instance IsString IsoXmlDescPreField where
257275instance IsString (TH.TypeQ -> IsoXmlDescPreAttribute) where
258276 fromString = IsoXmlDescPreAttribute
259277
278+instance IsString (TH.TypeQ -> IsoXmlDescPreContent) where
279+ fromString = IsoXmlDescPreContent
280+
260281instance IsString IsoXmlDescPreAttribute where
261282 fromString name = IsoXmlDescPreAttribute name ty
262283 where
263284 ty = (TH.conT . TH.mkName) ("Xml" ++ over _head C.toUpper name)
264285
286+instance IsString IsoXmlDescPreContent where
287+ fromString name = IsoXmlDescPreContent name ty
288+ where
289+ ty = (TH.conT . TH.mkName) ("Xml" ++ over _head C.toUpper name)
290+
265291instance s ~ String => IsString (s -> PrefixName) where
266292 fromString = PrefixName
267293
@@ -349,6 +375,14 @@ isoXmlGenerateDatatype (PrefixName strName' strPrefix') descRecordParts = do
349375 in if isNewtype
350376 then varStrictType fName (nonStrictType fType)
351377 else varStrictType fName (strictType fType)
378+ IsoXmlDescRecordContent descContent ->
379+ let
380+ IsoXmlDescContent contentStrName contentType = descContent
381+ fName = TH.mkName (fieldName contentStrName)
382+ fType = contentType
383+ in if isNewtype
384+ then varStrictType fName (nonStrictType fType)
385+ else varStrictType fName (strictType fType)
352386 if isNewtype
353387 -- generate a newtype instead to do less allocations later
354388 then newtypeD name (TH.recC name fields) [''Eq, ''Show, ''Generic]
@@ -384,6 +418,7 @@ isoXmlGenerateDatatype (PrefixName strName' strPrefix') descRecordParts = do
384418 XmlAttributePluralOptional -> [e|parseAttributeMaybe|]
385419 in
386420 [e|$attributeParse $exprAttributeStrName fromAttribute|]
421+ IsoXmlDescRecordContent _ -> [e|parseContent fromAttribute|]
387422 fromDomExpr = foldl (\e fe -> [e| $e <*> $fe |]) exprHeader exprRecordParts
388423 TH.instanceD
389424 (return [])
@@ -395,21 +430,27 @@ isoXmlGenerateDatatype (PrefixName strName' strPrefix') descRecordParts = do
395430 let
396431 exprFields = do
397432 descRecordPart <- descRecordParts
398− IsoXmlDescField fieldPlural rawName _ <-
399− maybeToList $ case descRecordPart of
400− IsoXmlDescRecordField descField -> Just descField
401− _ -> Nothing
402− let
403− fieldStrName = xmlLocalName rawName
404− fName = TH.mkName (fieldName fieldStrName)
405− exprFieldStrName = TH.litE (TH.stringL rawName)
406− exprForField = case fieldPlural of
407− XmlFieldPluralMandatory -> [e|id|]
408− _ -> [e|traverse|]
409− exprFieldValue = [e|$(TH.varE fName) $(TH.varE objName)|]
410− exprFieldRender =
411− [e|(\a -> XW.elementA $exprFieldStrName (toXmlParentAttributes a) a)|]
412− return [e|$exprForField $exprFieldRender $exprFieldValue|]
433+ case descRecordPart of
434+ IsoXmlDescRecordField (IsoXmlDescField fieldPlural rawName _) -> do
435+ let
436+ fieldStrName = xmlLocalName rawName
437+ fName = TH.mkName (fieldName fieldStrName)
438+ exprFieldStrName = TH.litE (TH.stringL rawName)
439+ exprForField = case fieldPlural of
440+ XmlFieldPluralMandatory -> [e|id|]
441+ _ -> [e|traverse|]
442+ exprFieldValue = [e|$(TH.varE fName) $(TH.varE objName)|]
443+ exprFieldRender =
444+ [e|(\a ->
445+ XW.elementA $exprFieldStrName (toXmlParentAttributes a) a)|]
446+ return [e|$exprForField $exprFieldRender $exprFieldValue|]
447+ IsoXmlDescRecordContent (IsoXmlDescContent rawName _) -> do
448+ let
449+ fieldStrName = xmlLocalName rawName
450+ fName = TH.mkName (fieldName fieldStrName)
451+ exprFieldValue = [e|$(TH.varE fName) $(TH.varE objName)|]
452+ return [e|XW.content . toXmlAttribute $ $exprFieldValue|]
453+ _ -> []
413454 toXmlExpr
414455 = TH.lamE [if null exprFields then TH.wildP else TH.varP objName]
415456 $ foldr (\fe e -> [e|$fe *> $e|]) [e|return ()|] exprFields
src/Text/XML/DOM/Parser/Internal/Content.hsnew file+28
@@ -0,0 +1,28 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Text.XML.DOM.Parser.Internal.Content where
3+import Control.Lens
4+import Control.Monad.Reader
5+import Data.Text as T
6+import Text.XML
7+import Text.XML.DOM.Parser hiding (getCurrentContent, parseContent)
8+
9+-- Get current content. If there are more than one content
10+-- they are intercalate with space like in xpath `text()`
11+--
12+getCurrentContent :: (Monad m) => DomParserT Identity m Text
13+getCurrentContent
14+ = T.intercalate " "
15+ . (\e -> [T.strip cs| (NodeContent cs) <- e])
16+ . elementNodes
17+ . runIdentity
18+ . _pdElements
19+ <$> ask
20+
21+parseContent
22+ :: (Monad m)
23+ => (Text -> Either Text a)
24+ -- ^ Content parser, return error msg if value is not parsed
25+ -> DomParserT Identity m a
26+parseContent parse
27+ = getCurrentContent
28+ >>= either (throwParserError . PEContentWrongFormat) return . parse
stack.yaml+1−1
@@ -1,4 +1,4 @@
1−resolver: lts-6.35
1+resolver: lts-10.0
22extra-deps:
33- dom-parser-3.0.0
44- generic-arbitrary-0.1.0
test/TestDefs.hs+2−1
@@ -4,7 +4,7 @@
44
55module TestDefs where
66
7−import Data.List.NonEmpty
7+-- import Data.List.NonEmpty
88import Data.THGen.XML
99import Test.QuickCheck.Arbitrary.Generic
1010import Test.QuickCheck.Instances ()
@@ -23,6 +23,7 @@ import Test.QuickCheck.Instances ()
2323 & "US"
2424
2525"Foo" =:= record
26+ ^ "Shmuux" [t|XmlQuux|]
2627 + "Bar"
2728 ? "Baz" [t|Text|]
2829 !% "Quux"
xml-isogen.cabal+2−1
@@ -1,5 +1,5 @@
11name: xml-isogen
2−version: 0.3.0
2+version: 0.3.1
33synopsis: Generate XML-isomorphic types
44description:
55 TemplateHaskell generators for XML-isomorphic data types, including
@@ -32,6 +32,7 @@ library
3232 , Data.THGen.XML
3333 , Text.XML.ParentAttributes
3434 other-modules: Data.THGen.Compat
35+ , Text.XML.DOM.Parser.Internal.Content
3536 build-depends: QuickCheck >= 2.8
3637 , base >=4.8 && <5
3738 , dom-parser >= 2.0.0