module Text.XML.HXT.Arrow.Pickle.Xml
where
import Control.Applicative (Applicative (..))
import Control.Arrow.ArrowList
import Control.Arrow.ListArrows
import Control.Monad ()
import Control.Monad.Except (MonadError (..))
import Control.Monad.State (MonadState (..), gets,
modify)
import Data.Char (isDigit)
import Data.List (foldl')
import Data.Map (Map)
import qualified Data.Map as M
import Data.Maybe (fromJust, fromMaybe)
import Text.XML.HXT.Arrow.Edit (xshowEscapeXml)
import Text.XML.HXT.Arrow.Pickle.Schema
import Text.XML.HXT.Arrow.ReadDocument (xread)
import Text.XML.HXT.Arrow.WriteDocument (writeDocumentToString)
import Text.XML.HXT.Arrow.XmlState
import Text.XML.HXT.DOM.Interface
import qualified Text.XML.HXT.DOM.ShowXml as XN
import qualified Text.XML.HXT.DOM.XmlNode as XN
data St = St { attributes :: [XmlTree]
, contents :: [XmlTree]
, nesting :: Int
, pname :: QName
, pelem :: Bool
} deriving (Show)
data PU a = PU { appPickle :: Pickler a
, appUnPickle :: Unpickler a
, theSchema :: Schema
}
type Pickler a = a -> St -> St
newtype Unpickler a = UP { runUP :: St -> (UnpickleVal a, St) }
type UnpickleVal a = Either UnpickleErr a
type UnpickleErr = (String, St)
instance Functor Unpickler where
fmap f u = UP $ \ st ->
let (r, st') = runUP u st in (fmap f r, st')
instance Applicative Unpickler where
pure a = UP $ \ st -> (Right a, st)
uf <*> ua = UP $ \ st ->
let (f, st') = runUP uf st in
case f of
Left err -> (Left err, st')
Right f' -> runUP (fmap f' ua) st'
instance Monad Unpickler where
return = pure
u >>= f = UP $ \ st ->
let (r, st') = runUP u st in
case r of
Left err -> (Left err, st')
Right v -> runUP (f v) st'
fail = throwMsg
instance MonadState St Unpickler where
get = UP $ \ st -> (Right st, st)
put st = UP $ \ _ -> (Right (), st)
instance MonadError UnpickleErr Unpickler where
throwError err
= UP $ \ st -> (Left err, st)
catchError u handler
= UP $ \ st ->
let (r, st') = runUP u st in
case r of
Left err -> runUP (handler err) st
_ -> (r, st')
throwMsg :: String -> Unpickler a
throwMsg msg = UP $ \ st -> (Left (msg, st), st)
mchoice :: Unpickler a -> (a -> Unpickler b) -> Unpickler b -> Unpickler b
mchoice u f v = UP $ \ st ->
let (r, st') = runUP u st in
case r of
Right x
-> runUP (f x) st'
Left e@(_msg, st'')
-> if nesting st'' == nesting st
then runUP v st
else (Left e, st')
liftMaybe :: String -> Maybe a -> Unpickler a
liftMaybe e v = case v of
Nothing -> throwMsg e
Just x -> return x
liftUnpickleVal :: UnpickleVal a -> Unpickler a
liftUnpickleVal v = UP $ \ st -> (v, st)
getCont :: Unpickler XmlTree
getCont = do cs <- gets contents
case cs of
[] -> throwMsg "no more contents to be read"
(x : xs) -> do modify (\ s -> s {contents = xs})
return x
getAtt :: QName -> Unpickler XmlTree
getAtt qn = do as <- gets attributes
case findAtt as of
Nothing -> throwMsg $ "no attribute value found for " ++ show qn
Just (a, as') -> do modify (\ s -> s {attributes = as'})
return a
where
findAtt = findElem (maybe False (== qn) . XN.getAttrName)
getNSAtt :: String -> Unpickler ()
getNSAtt ns = do as <- gets attributes
case findNS as of
Nothing -> throwMsg $
"no namespace declaration found for namespace " ++ show ns
Just (_a, as') -> do modify (\ s -> s {attributes = as'})
return ()
where
isNS t = (fromMaybe False . fmap isNameSpaceName . XN.getAttrName $ t)
&&
XN.xshow (XN.getChildren t) == ns
findNS = findElem isNS
emptySt :: St
emptySt = St { attributes = []
, contents = []
, nesting = 0
, pname = mkName "/"
, pelem = True
}
putAtt :: QName -> [XmlTree] -> St -> St
putAtt qn v s = s {attributes = x : attributes s}
where
x = XN.mkAttr qn v
putCont :: XmlTree -> St -> St
putCont x s = s {contents = x : contents s}
findElem :: (a -> Bool) -> [a] -> Maybe (a, [a])
findElem p = find' id
where
find' _ [] = Nothing
find' prefix (x : xs)
| p x = Just (x, prefix xs)
| otherwise = find' (prefix . (x:)) xs
formatSt :: St -> String
formatSt st = fcx ++
fa (attributes st) ++
fc (contents st)
where
fcx = "\n" ++ "context: " ++
( if pelem st
then "element"
else "attribute"
) ++
" " ++ show (pname st)
fc [] = ""
fc cs = "\n" ++ "contents: " ++ formatXML cs
fa [] = ""
fa as = "\n" ++ "attributes: " ++ formatXML as
formatXML = format 80 . showXML
showXML = concat . runLA ( xshowEscapeXml unlistA )
format n s = let s' = take (n + 1) s in
if length s' <= n then s' else take n s ++ "..."
pickleDoc :: PU a -> a -> XmlTree
pickleDoc p v = XN.mkRoot (attributes st) (contents st)
where
st = appPickle p v emptySt
unpickleDoc :: PU a -> XmlTree -> Maybe a
unpickleDoc p = either (const Nothing) Just
. unpickleDoc' p
unpickleDoc' :: PU a -> XmlTree -> Either String a
unpickleDoc' p t
| XN.isRoot t = mapErr $
unpickleElem' p 0 t
| otherwise = unpickleDoc' p (XN.mkRoot [] [t])
where
mapErr = either ( Left .
\ (msg, st) -> msg ++ formatSt st
) Right
unpickleElem' :: PU a -> Int -> XmlTree -> UnpickleVal a
unpickleElem' p l t
= fst
. runUP (appUnPickle p)
$ St { attributes = fromMaybe [] .
XN.getAttrl $ t
, contents = XN.getChildren t
, nesting = l
, pname = fromJust .
XN.getName $ t
, pelem = XN.isElem t
}
showPickled :: (XmlPickler a) => SysConfigList -> a -> String
showPickled a = concat . (pickleDoc xpickle >>> runLA (writeDocumentToString a))
xpZero :: String -> PU a
xpZero err = PU { appPickle = const id
, appUnPickle = throwMsg err
, theSchema = scNull
}
xpUnit :: PU ()
xpUnit = xpLift ()
xpCheckEmptyContents :: PU a -> PU a
xpCheckEmptyContents pa = PU { appPickle = appPickle pa
, appUnPickle = do res <- appUnPickle pa
cs <- gets contents
if null cs
then return res
else contentsLeft
, theSchema = scNull
}
where
contentsLeft = throwMsg
"xpCheckEmptyContents: unprocessed XML content detected"
xpCheckEmptyAttributes :: PU a -> PU a
xpCheckEmptyAttributes pa
= PU { appPickle = appPickle pa
, appUnPickle = do res <- appUnPickle pa
as <- gets attributes
if null as
then return res
else attributesLeft
, theSchema = scNull
}
where
attributesLeft = throwMsg
"xpCheckEmptyAttributes: unprocessed XML attribute(s) detected"
xpCheckEmpty :: PU a -> PU a
xpCheckEmpty = xpCheckEmptyAttributes . xpCheckEmptyContents
xpLift :: a -> PU a
xpLift x = PU { appPickle = const id
, appUnPickle = return x
, theSchema = scEmpty
}
xpLiftMaybe :: Maybe a -> PU a
xpLiftMaybe v = (xpLiftMaybe'' v) { theSchema = scOption scEmpty }
where
xpLiftMaybe'' Nothing = xpZero "xpLiftMaybe: got Nothing"
xpLiftMaybe'' (Just x) = xpLift x
xpLiftEither :: Either String a -> PU a
xpLiftEither v = (xpLiftEither'' v) { theSchema = scOption scEmpty }
where
xpLiftEither'' (Left err) = xpZero err
xpLiftEither'' (Right x) = xpLift x
xpSeq :: (b -> a) -> PU a -> (a -> PU b) -> PU b
xpSeq f pa k
= PU { appPickle = ( \ b ->
let a = f b in
appPickle pa a . appPickle (k a) b
)
, appUnPickle = appUnPickle pa >>= (appUnPickle . k)
, theSchema = undefined
}
xpSeq' :: PU () -> PU a -> PU a
xpSeq' pa = xpWrap ( snd
, \ y -> ((), y)
) .
xpPair pa
xpChoice :: PU b -> PU a -> (a -> PU b) -> Unpickler b
xpChoice pb pa k = mchoice (appUnPickle pa) (appUnPickle . k) (appUnPickle pb)
xpWrap :: (a -> b, b -> a) -> PU a -> PU b
xpWrap (i, j) pa = (xpSeq j pa (xpLift . i)) { theSchema = theSchema pa }
xpWrapMaybe :: (a -> Maybe b, b -> a) -> PU a -> PU b
xpWrapMaybe (i, j) pa = (xpSeq j pa (xpLiftMaybe . i)) { theSchema = theSchema pa }
xpWrapEither :: (a -> Either String b, b -> a) -> PU a -> PU b
xpWrapEither (i, j) pa = (xpSeq j pa (xpLiftEither . i)) { theSchema = theSchema pa }
xpPair :: PU a -> PU b -> PU (a, b)
xpPair pa pb
= ( xpSeq fst pa (\ a ->
xpSeq snd pb (\ b ->
xpLift (a,b)))
) { theSchema = scSeq (theSchema pa) (theSchema pb) }
xpTriple :: PU a -> PU b -> PU c -> PU (a, b, c)
xpTriple pa pb pc
= xpWrap (toTriple, fromTriple) (xpPair pa (xpPair pb pc))
where
toTriple ~(a, ~(b, c)) = (a, b, c )
fromTriple ~(a, b, c ) = (a, (b, c))
xp4Tuple :: PU a -> PU b -> PU c -> PU d -> PU (a, b, c, d)
xp4Tuple pa pb pc pd
= xpWrap (toQuad, fromQuad) (xpPair pa (xpPair pb (xpPair pc pd)))
where
toQuad ~(a, ~(b, ~(c, d))) = (a, b, c, d )
fromQuad ~(a, b, c, d ) = (a, (b, (c, d)))
xp5Tuple :: PU a -> PU b -> PU c -> PU d -> PU e -> PU (a, b, c, d, e)
xp5Tuple pa pb pc pd pe
= xpWrap (toQuint, fromQuint) (xpPair pa (xpPair pb (xpPair pc (xpPair pd pe))))
where
toQuint ~(a, ~(b, ~(c, ~(d, e)))) = (a, b, c, d, e )
fromQuint ~(a, b, c, d, e ) = (a, (b, (c, (d, e))))
xp6Tuple :: PU a -> PU b -> PU c -> PU d -> PU e -> PU f -> PU (a, b, c, d, e, f)
xp6Tuple pa pb pc pd pe pf
= xpWrap (toSix, fromSix) (xpPair pa (xpPair pb (xpPair pc (xpPair pd (xpPair pe pf)))))
where
toSix ~(a, ~(b, ~(c, ~(d, ~(e, f))))) = (a, b, c, d, e, f )
fromSix ~(a, b, c, d, e, f) = (a, (b, (c, (d, (e, f)))))
xp7Tuple :: PU a -> PU b -> PU c -> PU d -> PU e ->
PU f -> PU g -> PU (a, b, c, d, e, f, g)
xp7Tuple a b c d e f g
= xpWrap ( \ (a, (b, c, d, e, f, g)) -> (a, b, c, d, e, f, g)
, \ (a, b, c, d, e, f, g) -> (a, (b, c, d, e, f, g))
)
(xpPair a (xp6Tuple b c d e f g))
xp8Tuple :: PU a -> PU b -> PU c -> PU d -> PU e ->
PU f -> PU g -> PU h -> PU (a, b, c, d, e, f, g, h)
xp8Tuple a b c d e f g h
= xpWrap ( \ ((a, b), (c, d, e, f, g, h)) -> (a, b, c, d, e, f, g, h)
, \ (a, b, c, d, e, f, g, h) -> ((a, b), (c, d, e, f, g, h))
)
(xpPair (xpPair a b) (xp6Tuple c d e f g h))
xp9Tuple :: PU a -> PU b -> PU c -> PU d -> PU e ->
PU f -> PU g -> PU h -> PU i -> PU (a, b, c, d, e, f, g, h, i)
xp9Tuple a b c d e f g h i
= xpWrap ( \ ((a, b, c), (d, e, f, g, h, i)) -> (a, b, c, d, e, f, g, h, i)
, \ (a, b, c, d, e, f, g, h, i) -> ((a, b, c), (d, e, f, g, h, i))
)
(xpPair (xpTriple a b c) (xp6Tuple d e f g h i))
xp10Tuple :: PU a -> PU b -> PU c -> PU d -> PU e ->
PU f -> PU g -> PU h -> PU i -> PU j ->
PU (a, b, c, d, e, f, g, h, i, j)
xp10Tuple a b c d e f g h i j
= xpWrap ( \ ((a, b, c, d), (e, f, g, h, i, j)) -> (a, b, c, d, e, f, g, h, i, j)
, \ (a, b, c, d, e, f, g, h, i, j) -> ((a, b, c, d), (e, f, g, h, i, j))
)
(xpPair (xp4Tuple a b c d) (xp6Tuple e f g h i j))
xp11Tuple :: PU a -> PU b -> PU c -> PU d -> PU e ->
PU f -> PU g -> PU h -> PU i -> PU j ->
PU k -> PU (a, b, c, d, e, f, g, h, i, j, k)
xp11Tuple a b c d e f g h i j k
= xpWrap ( \ ((a, b, c, d, e), (f, g, h, i, j, k)) -> (a, b, c, d, e, f, g, h, i, j, k)
, \ (a, b, c, d, e, f, g, h, i, j, k) -> ((a, b, c, d, e), (f, g, h, i, j, k))
)
(xpPair (xp5Tuple a b c d e) (xp6Tuple f g h i j k))
xp12Tuple :: PU a -> PU b -> PU c -> PU d -> PU e ->
PU f -> PU g -> PU h -> PU i -> PU j ->
PU k -> PU l -> PU (a, b, c, d, e, f, g, h, i, j, k, l)
xp12Tuple a b c d e f g h i j k l
= xpWrap ( \ ((a, b, c, d, e, f), (g, h, i, j, k, l)) -> (a, b, c, d, e, f, g, h, i, j, k, l)
, \ (a, b, c, d, e, f, g, h, i, j, k, l) -> ((a, b, c, d, e, f), (g, h, i, j, k, l))
)
(xpPair (xp6Tuple a b c d e f) (xp6Tuple g h i j k l))
xp13Tuple :: PU a -> PU b -> PU c -> PU d -> PU e ->
PU f -> PU g -> PU h -> PU i -> PU j ->
PU k -> PU l -> PU m -> PU (a, b, c, d, e, f, g, h, i, j, k, l, m)
xp13Tuple a b c d e f g h i j k l m
= xpWrap ( \ (a, (b, c, d, e, f, g), (h, i, j, k, l, m)) -> (a, b, c, d, e, f, g, h, i, j, k, l, m)
, \ (a, b, c, d, e, f, g, h, i, j, k, l, m) -> (a, (b, c, d, e, f, g), (h, i, j, k, l, m))
)
(xpTriple a (xp6Tuple b c d e f g) (xp6Tuple h i j k l m))
xp14Tuple :: PU a -> PU b -> PU c -> PU d -> PU e ->
PU f -> PU g -> PU h -> PU i -> PU j ->
PU k -> PU l -> PU m -> PU n -> PU (a, b, c, d, e, f, g, h, i, j, k, l, m, n)
xp14Tuple a b c d e f g h i j k l m n
= xpWrap ( \ ((a, b), (c, d, e, f, g, h), (i, j, k, l, m, n)) -> (a, b, c, d, e, f, g, h, i, j, k, l, m, n)
, \ (a, b, c, d, e, f, g, h, i, j, k, l, m, n) -> ((a, b), (c, d, e, f, g, h), (i, j, k, l, m, n))
)
(xpTriple (xpPair a b) (xp6Tuple c d e f g h) (xp6Tuple i j k l m n))
xp15Tuple :: PU a -> PU b -> PU c -> PU d -> PU e ->
PU f -> PU g -> PU h -> PU i -> PU j ->
PU k -> PU l -> PU m -> PU n -> PU o ->
PU (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o)
xp15Tuple a b c d e f g h i j k l m n o
= xpWrap ( \ ((a, b, c), (d, e, f, g, h, i), (j, k, l, m, n, o)) -> (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o)
, \ (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) -> ((a, b, c), (d, e, f, g, h, i), (j, k, l, m, n, o))
)
(xpTriple (xpTriple a b c) (xp6Tuple d e f g h i) (xp6Tuple j k l m n o))
xp16Tuple :: PU a -> PU b -> PU c -> PU d -> PU e ->
PU f -> PU g -> PU h -> PU i -> PU j ->
PU k -> PU l -> PU m -> PU n -> PU o ->
PU p -> PU (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)
xp16Tuple a b c d e f g h i j k l m n o p
= xpWrap ( \ ((a, b, c, d), (e, f, g, h, i, j), (k, l, m, n, o, p)) -> (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)
, \ (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) -> ((a, b, c, d), (e, f, g, h, i, j), (k, l, m, n, o, p))
)
(xpTriple (xp4Tuple a b c d) (xp6Tuple e f g h i j) (xp6Tuple k l m n o p))
xp17Tuple :: PU a -> PU b -> PU c -> PU d -> PU e ->
PU f -> PU g -> PU h -> PU i -> PU j ->
PU k -> PU l -> PU m -> PU n -> PU o ->
PU p -> PU q -> PU (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q)
xp17Tuple a b c d e f g h i j k l m n o p q
= xpWrap ( \ ((a, b, c, d, e), (f, g, h, i, j, k), (l, m, n, o, p, q)) -> (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q)
, \ (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q) -> ((a, b, c, d, e), (f, g, h, i, j, k), (l, m, n, o, p, q))
)
(xpTriple (xp5Tuple a b c d e) (xp6Tuple f g h i j k) (xp6Tuple l m n o p q))
xp18Tuple :: PU a -> PU b -> PU c -> PU d -> PU e ->
PU f -> PU g -> PU h -> PU i -> PU j ->
PU k -> PU l -> PU m -> PU n -> PU o ->
PU p -> PU q -> PU r -> PU (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r)
xp18Tuple a b c d e f g h i j k l m n o p q r
= xpWrap ( \ ((a, b, c, d, e, f), (g, h, i, j, k, l), (m, n, o, p, q, r)) -> (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r)
, \ (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r) -> ((a, b, c, d, e, f), (g, h, i, j, k, l), (m, n, o, p, q, r))
)
(xpTriple (xp6Tuple a b c d e f) (xp6Tuple g h i j k l) (xp6Tuple m n o p q r))
xp19Tuple :: PU a -> PU b -> PU c -> PU d -> PU e ->
PU f -> PU g -> PU h -> PU i -> PU j ->
PU k -> PU l -> PU m -> PU n -> PU o ->
PU p -> PU q -> PU r -> PU s -> PU (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s)
xp19Tuple a b c d e f g h i j k l m n o p q r s
= xpWrap ( \ (a, (b, c, d, e, f, g), (h, i, j, k, l, m), (n, o, p, q, r, s)) -> (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s)
, \ (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s) -> (a, (b, c, d, e, f, g), (h, i, j, k, l, m), (n, o, p, q, r, s))
)
(xp4Tuple a (xp6Tuple b c d e f g) (xp6Tuple h i j k l m) (xp6Tuple n o p q r s))
xp20Tuple :: PU a -> PU b -> PU c -> PU d -> PU e ->
PU f -> PU g -> PU h -> PU i -> PU j ->
PU k -> PU l -> PU m -> PU n -> PU o ->
PU p -> PU q -> PU r -> PU s -> PU t ->
PU (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t)
xp20Tuple a b c d e f g h i j k l m n o p q r s t
= xpWrap ( \ ((a, b), (c, d, e, f, g, h), (i, j, k, l, m, n), (o, p, q, r, s, t)) -> (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t)
, \ (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t) -> ((a, b), (c, d, e, f, g, h), (i, j, k, l, m, n), (o, p, q, r, s, t))
)
(xp4Tuple (xpPair a b) (xp6Tuple c d e f g h) (xp6Tuple i j k l m n) (xp6Tuple o p q r s t))
xp21Tuple :: PU a -> PU b -> PU c -> PU d -> PU e ->
PU f -> PU g -> PU h -> PU i -> PU j ->
PU k -> PU l -> PU m -> PU n -> PU o ->
PU p -> PU q -> PU r -> PU s -> PU t ->
PU u -> PU (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u)
xp21Tuple a b c d e f g h i j k l m n o p q r s t u
= xpWrap ( \ ((a, b, c), (d, e, f, g, h, i), (j, k, l, m, n, o), (p, q, r, s, t, u)) -> (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u)
, \ (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u) -> ((a, b, c), (d, e, f, g, h, i), (j, k, l, m, n, o), (p, q, r, s, t, u))
)
(xp4Tuple (xpTriple a b c) (xp6Tuple d e f g h i) (xp6Tuple j k l m n o) (xp6Tuple p q r s t u))
xp22Tuple :: PU a -> PU b -> PU c -> PU d -> PU e ->
PU f -> PU g -> PU h -> PU i -> PU j ->
PU k -> PU l -> PU m -> PU n -> PU o ->
PU p -> PU q -> PU r -> PU s -> PU t ->
PU u -> PU v -> PU (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v)
xp22Tuple a b c d e f g h i j k l m n o p q r s t u v
= xpWrap ( \ ((a, b, c, d), (e, f, g, h, i, j), (k, l, m, n, o, p), (q, r, s, t, u, v)) -> (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v)
, \ (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v) -> ((a, b, c, d), (e, f, g, h, i, j), (k, l, m, n, o, p), (q, r, s, t, u, v))
)
(xp4Tuple (xp4Tuple a b c d) (xp6Tuple e f g h i j) (xp6Tuple k l m n o p) (xp6Tuple q r s t u v))
xp23Tuple :: PU a -> PU b -> PU c -> PU d -> PU e ->
PU f -> PU g -> PU h -> PU i -> PU j ->
PU k -> PU l -> PU m -> PU n -> PU o ->
PU p -> PU q -> PU r -> PU s -> PU t ->
PU u -> PU v -> PU w -> PU (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w)
xp23Tuple a b c d e f g h i j k l m n o p q r s t u v w
= xpWrap ( \ ((a, b, c, d, e), (f, g, h, i, j, k), (l, m, n, o, p, q), (r, s, t, u, v, w)) -> (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w)
, \ (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w) -> ((a, b, c, d, e), (f, g, h, i, j, k), (l, m, n, o, p, q), (r, s, t, u, v, w))
)
(xp4Tuple (xp5Tuple a b c d e) (xp6Tuple f g h i j k) (xp6Tuple l m n o p q) (xp6Tuple r s t u v w))
xp24Tuple :: PU a -> PU b -> PU c -> PU d -> PU e ->
PU f -> PU g -> PU h -> PU i -> PU j ->
PU k -> PU l -> PU m -> PU n -> PU o ->
PU p -> PU q -> PU r -> PU s -> PU t ->
PU u -> PU v -> PU w -> PU x -> PU (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x)
xp24Tuple a b c d e f g h i j k l m n o p q r s t u v w x
= xpWrap ( \ ((a, b, c, d, e, f), (g, h, i, j, k, l), (m, n, o, p, q, r), (s, t, u, v, w, x)) -> (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x)
, \ (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x) -> ((a, b, c, d, e, f), (g, h, i, j, k, l), (m, n, o, p, q, r), (s, t, u, v, w, x))
)
(xp4Tuple (xp6Tuple a b c d e f) (xp6Tuple g h i j k l) (xp6Tuple m n o p q r) (xp6Tuple s t u v w x))
xpText :: PU String
xpText = xpTextDT scString1
xpTextDT :: Schema -> PU String
xpTextDT sc = PU { appPickle = putCont . XN.mkText
, appUnPickle = do t <- getCont
liftMaybe "xpText: XML text expected" $ XN.getText t
, theSchema = sc
}
xpText0 :: PU String
xpText0 = xpText0DT scString1
xpText0DT :: Schema -> PU String
xpText0DT sc = xpWrap (fromMaybe "", emptyToNothing) $
xpOption $
xpTextDT sc
where
emptyToNothing "" = Nothing
emptyToNothing x = Just x
xpPrim :: (Read a, Show a) => PU a
xpPrim = xpWrapEither (readMaybe, show) xpText
where
readMaybe :: Read a => String -> Either String a
readMaybe str = val (reads str)
where
val [(x,"")] = Right x
val _ = Left $ "xpPrim: reading string " ++ show str ++ " failed"
xpInt :: PU Int
xpInt = xpWrapEither (readMaybe, show) xpText
where
readMaybe xs
| all isDigit xs = Right . foldl' (\ r c -> 10 * r + (fromEnum c fromEnum '0')) 0 $ xs
readMaybe ('-' : xs) = fmap (0 ) . readMaybe $ xs
readMaybe ('+' : xs) = readMaybe $ xs
readMaybe xs = Left $ "xpInt: reading an Int from string " ++ show xs ++ " failed"
xpTree :: PU XmlTree
xpTree = PU { appPickle = putCont
, appUnPickle = getCont
, theSchema = Any
}
xpTrees :: PU [XmlTree]
xpTrees = (xpList xpTree) { theSchema = Any }
xpXmlText :: PU String
xpXmlText = xpWrap ( showXML, readXML ) $ xpTrees
where
showXML = concat . runLA ( xshowEscapeXml unlistA )
readXML = runLA xread
xpOption :: PU a -> PU (Maybe a)
xpOption pa = PU { appPickle = ( \ a ->
case a of
Nothing -> id
Just x -> appPickle pa x
)
, appUnPickle = xpChoice (xpLift Nothing) pa (xpLift . Just)
, theSchema = scOption (theSchema pa)
}
xpDefault :: (Eq a) => a -> PU a -> PU a
xpDefault df = xpWrap ( fromMaybe df
, \ x -> if x == df then Nothing else Just x
) .
xpOption
xpList :: PU a -> PU [a]
xpList pa = PU { appPickle = ( \ a ->
case a of
[] -> id
_:_ -> appPickle pc a
)
, appUnPickle = xpChoice
(xpLift [])
pa
(\ x -> xpSeq id (xpList pa) (\xs -> xpLift (x:xs)))
, theSchema = scList (theSchema pa)
}
where
pc = xpSeq head pa (\ x ->
xpSeq tail (xpList pa) (\ xs ->
xpLift (x:xs) ))
xpList1 :: PU a -> PU [a]
xpList1 pa = ( xpWrap (\ (x, xs) -> x : xs
,\ x -> (head x, tail x)
) $
xpPair pa (xpList pa)
) { theSchema = scList1 (theSchema pa) }
xpMap :: Ord k => String -> String -> PU k -> PU v -> PU (Map k v)
xpMap en an xpk xpv
= xpWrap ( M.fromList
, M.toList
) $
xpList $
xpElem en $
xpPair ( xpAttr an $ xpk ) xpv
xpAlt :: (a -> Int) -> [PU a] -> PU a
xpAlt tag ps = PU { appPickle = \ a ->
appPickle (ps !! tag a) a
, appUnPickle = case ps of
[] -> throwMsg "xpAlt: no matching unpickler found for a sum datatype"
pa:ps1 -> xpChoice (xpAlt tag ps1) pa xpLift
, theSchema = scAlts (map theSchema ps)
}
xpElemQN :: QName -> PU a -> PU a
xpElemQN qn pa = PU { appPickle = ( \ a ->
let st' = appPickle pa a emptySt in
putCont (XN.mkElement qn (attributes st') (contents st'))
)
, appUnPickle = upElem
, theSchema = scElem (qualifiedName qn) (theSchema pa)
}
where
upElem = do t <- getCont
n <- liftMaybe "xpElem: XML element expected" $ XN.getElemName t
if n /= qn
then throwMsg ("xpElem: got element name " ++ show n ++ ", but expected " ++ show qn)
else do l <- gets nesting
liftUnpickleVal $ unpickleElem' (xpCheckEmpty pa) (l + 1) t
xpElem :: String -> PU a -> PU a
xpElem = xpElemQN . mkName
xpElemNS :: String -> String -> String -> PU a -> PU a
xpElemNS ns px lp
= xpElemQN $ mkQName px lp ns
xpElemWithAttrValue :: String -> String -> String -> PU a -> PU a
xpElemWithAttrValue name an av pa
= xpElem name $
xpAddFixedAttr an av $
pa
xpAttrQN :: QName -> PU a -> PU a
xpAttrQN qn pa = PU { appPickle = ( \ a ->
let st' = appPickle pa a emptySt in
putAtt qn (contents st')
)
, appUnPickle = upAttr
, theSchema = scAttr (qualifiedName qn) (theSchema pa)
}
where
upAttr = do a <- getAtt qn
l <- gets nesting
liftUnpickleVal $ unpickleElem' (xpCheckEmptyContents pa) l a
xpAttr :: String -> PU a -> PU a
xpAttr = xpAttrQN . mkName
xpAttrNS :: String -> String -> String -> PU a -> PU a
xpAttrNS ns px lp
= xpAttrQN (mkQName px lp ns)
xpTextAttr :: String -> PU String
xpTextAttr = flip xpAttr xpText
xpAttrImplied :: String -> PU a -> PU (Maybe a)
xpAttrImplied name pa
= xpOption $ xpAttr name pa
xpAttrFixed :: String -> String -> PU ()
xpAttrFixed name val
= ( xpWrapEither ( \ v ->
if v == val
then Right ()
else Left ( "xpAttrFixed: value "
++ show val
++ " expected, but got "
++ show v
)
, const val
) $
xpAttr name xpText
) { theSchema = scAttr name (scFixed val) }
xpAddFixedAttr :: String -> String -> PU a -> PU a
xpAddFixedAttr name val
= xpSeq' $ xpAttrFixed name val
xpAddNSDecl :: String -> String -> PU a -> PU a
xpAddNSDecl name val
= xpSeq' $ xpAttrNSDecl name' val
where
name'
| null name = "xmlns"
| otherwise = "xmlns:" ++ name
xpAttrNSDecl :: String -> String -> PU ()
xpAttrNSDecl name ns
= PU { appPickle = const $ putAtt (mkName name) [XN.mkText ns]
, appUnPickle = getNSAtt ns
, theSchema = scAttr name (scFixed ns)
}
xpIgnoreCont :: LA XmlTree XmlTree -> PU ()
xpIgnoreCont = xpIgnoreInput $ \ mf s -> s {contents = mf $ contents s}
xpIgnoreAttr :: LA XmlTree XmlTree -> PU ()
xpIgnoreAttr = xpIgnoreInput $ \ mf s -> s {attributes = mf $ attributes s}
xpFilterCont :: LA XmlTree XmlTree -> PU a -> PU a
xpFilterCont f = xpSeq' $ xpIgnoreCont f
xpFilterAttr :: LA XmlTree XmlTree -> PU a -> PU a
xpFilterAttr f = xpSeq' $ xpIgnoreAttr f
xpIgnoreInput :: (([XmlTree] -> [XmlTree]) -> St -> St) -> LA XmlTree XmlTree -> PU ()
xpIgnoreInput m f
= PU { appPickle = const id
, appUnPickle = do modify (m filterCont)
return ()
, theSchema = scNull
}
where
filterCont = runLA (unlistA >>> f)
class XmlPickler a where
xpickle :: PU a
instance XmlPickler Int where
xpickle = xpPrim
instance XmlPickler Integer where
xpickle = xpPrim
instance XmlPickler () where
xpickle = xpUnit
instance (XmlPickler a, XmlPickler b) => XmlPickler (a,b) where
xpickle = xpPair xpickle xpickle
instance (XmlPickler a, XmlPickler b, XmlPickler c) => XmlPickler (a,b,c) where
xpickle = xpTriple xpickle xpickle xpickle
instance (XmlPickler a, XmlPickler b, XmlPickler c, XmlPickler d) => XmlPickler (a,b,c,d) where
xpickle = xp4Tuple xpickle xpickle xpickle xpickle
instance (XmlPickler a, XmlPickler b, XmlPickler c, XmlPickler d, XmlPickler e) => XmlPickler (a,b,c,d,e) where
xpickle = xp5Tuple xpickle xpickle xpickle xpickle xpickle
instance XmlPickler a => XmlPickler [a] where
xpickle = xpList xpickle
instance XmlPickler a => XmlPickler (Maybe a) where
xpickle = xpOption xpickle