{-# OPTIONS -fglasgow-exts #-}
module XML (tests) where
import Test.HUnit
import Control.Monad
import Data.Maybe
import Data.Generics
import CompanyDatatypes
data Element = Elem Name [Attribute] [Content]
deriving (Show, Eq, Typeable, Data)
data Content = CElem Element
| CString Bool CharData
| CRef Reference
| CMisc Misc
deriving (Show, Eq, Typeable, Data)
type CharData = String
type Attribute = ()
type Reference = ()
type Misc = ()
data2content :: Data a => a -> [Content]
data2content = element
`ext1Q` list
`extQ` string
`extQ` float
where
element x = [CElem (Elem (tyconUQname (dataTypeName (dataTypeOf x)))
[]
(concat (gmapQ data2content x)))]
list :: Data a => [a] -> [Content]
list = concat . map data2content
string :: String -> [Content]
string x = [CString True x]
float :: Float -> [Content]
float x = [CString True (show x)]
content2data :: forall a. Data a => ReadX a
content2data = result
where
result = element
`ext1R` list
`extR` string
`extR` float
myType = myTypeOf result
where
myTypeOf :: forall a. ReadX a -> a
myTypeOf = undefined
element = do c <- readX
case c of
(CElem (Elem x as cs))
| as == []
&& x == (tyconUQname (dataTypeName (dataTypeOf myType)))
-> alts cs
_ -> mzero
list :: forall a. Data a => ReadX [a]
list = ( do h <- content2data
t <- list
return (h:t) )
`mplus` return []
alts cs = foldr (mplus . recurse cs) mzero shapes
shapes = map fromConstr consOf
consOf = dataTypeConstrs
$ dataTypeOf
$ myType
recurse cs x = maybe mzero
return
(runReadX (gmapM (const content2data) x) cs)
string :: ReadX String
string = do c <- readX
case c of
(CString _ x) -> return x
_ -> mzero
float :: ReadX Float
float = do c <- readX
case c of
(CString _ x) -> return (read x)
_ -> mzero
newtype ReadX a =
ReadX { unReadX :: [Content]
-> Maybe ([Content], a) }
runReadX x y = case unReadX x y of
Just ([],y) -> Just y
_ -> Nothing
readX :: ReadX Content
readX = ReadX (\x -> if null x
then Nothing
else Just (tail x, head x)
)
instance Monad ReadX where
return x = ReadX (\y -> Just (y,x))
c >>= f = ReadX (\x -> case unReadX c x of
Nothing -> Nothing
Just (x', a) -> unReadX (f a) x'
)
instance MonadPlus ReadX where
mzero = ReadX (const Nothing)
f `mplus` g = ReadX (\x -> case unReadX f x of
Nothing -> unReadX g x
y -> y
)
tests = ( genCom
, ( data2content genCom
, ( zigzag person1 :: Maybe Person
, ( zigzag genCom :: Maybe Company
, ( zigzag genCom == Just genCom
))))) ~=? output
where
zigzag :: Data a => a -> Maybe a
zigzag = runReadX content2data . data2content
output = (C [D "Research" (E (P "Laemmel" "Amsterdam") (S 8000.0)) [PU (E (P "Joost" "Amsterdam") (S 1000.0)),PU (E (P "Marlow" "Cambridge") (S 2000.0))],D "Strategy" (E (P "Blair" "London") (S 100000.0)) []],([CElem (Elem "Company" [] [CElem (Elem "Dept" [] [CString True "Research",CElem (Elem "Employee" [] [CElem (Elem "Person" [] [CString True "Laemmel",CString True "Amsterdam"]),CElem (Elem "Salary" [] [CString True "8000.0"])]),CElem (Elem "Unit" [] [CElem (Elem "Employee" [] [CElem (Elem "Person" [] [CString True "Joost",CString True "Amsterdam"]),CElem (Elem "Salary" [] [CString True "1000.0"])])]),CElem (Elem "Unit" [] [CElem (Elem "Employee" [] [CElem (Elem "Person" [] [CString True "Marlow",CString True "Cambridge"]),CElem (Elem "Salary" [] [CString True "2000.0"])])])]),CElem (Elem "Dept" [] [CString True "Strategy",CElem (Elem "Employee" [] [CElem (Elem "Person" [] [CString True "Blair",CString True "London"]),CElem (Elem "Salary" [] [CString True "100000.0"])])])])],(Just (P "Lazy" "Home"),(Just (C [D "Research" (E (P "Laemmel" "Amsterdam") (S 8000.0)) [PU (E (P "Joost" "Amsterdam") (S 1000.0)),PU (E (P "Marlow" "Cambridge") (S 2000.0))],D "Strategy" (E (P "Blair" "London") (S 100000.0)) []]),True))))