invertible-hxt-0.1: Text/XML/HXT/Arrow/Pickle/Xml/Invertible.hs
-- |Allow combining 'PU's using "Control.Invertible.Monoidal".
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Text.XML.HXT.Arrow.Pickle.Xml.Invertible
( module Text.XML.HXT.Arrow.Pickle.Xml
, module Control.Invertible.Monoidal
, xpWhitespace
, xpTrim
, xpAnyCont
, xpAnyAttrs
, xpAny
, xpAnyElem
) where
import Control.Invertible.Monoidal
import Control.Monad.State.Class (modify, state)
import Data.Char.Properties.XMLCharProps (isXmlSpaceChar)
import qualified Data.Invertible as Inv
import Data.List (partition)
import Data.Void (absurd)
import Text.XML.HXT.Arrow.Pickle.Schema (Schema(Any), scEmpty, scSeq, scAlt, scNull)
import Text.XML.HXT.Arrow.Pickle.Xml
import qualified Text.XML.HXT.Core as HXT
import qualified Text.XML.HXT.DOM.XmlNode as XN
instance Inv.Functor PU where
fmap (f Inv.:<->: g) p = PU -- xpWrap
{ appPickle = appPickle p . g
, appUnPickle = fmap f $ appUnPickle p
, theSchema = theSchema p
}
instance Monoidal PU where
unit = xpUnit
p >*< q = PU -- xpPair
{ appPickle = \(a, b) -> appPickle p a . appPickle q b
, appUnPickle = do
a <- appUnPickle p
b <- appUnPickle q
return (a, b)
, theSchema = theSchema p `scSeq` theSchema q
}
instance MonoidalAlt PU where
zero = PU
{ appPickle = \a _ -> absurd a
, appUnPickle = throwMsg "PU.zero"
, theSchema = scNull
}
p >|< q = PU
{ appPickle = either (appPickle p) (appPickle q)
, appUnPickle = mchoice (Left <$> appUnPickle p) return (Right <$> appUnPickle q)
, theSchema = theSchema p `scAlt` theSchema q
}
-- |Ignore any whitespace and produce nothing
xpWhitespace :: PU ()
xpWhitespace = PU
{ appPickle = const id
, appUnPickle = modify $ \s -> s{ contents = dropWhile (any (all isXmlSpaceChar) . XN.getText) $ contents s }
, theSchema = scEmpty
}
-- |Ignore leading whitespace
xpTrim :: PU a -> PU a
xpTrim = (xpWhitespace *<)
-- |Like 'xpTrees' but more efficient
xpAnyCont :: PU HXT.XmlTrees
xpAnyCont = PU
{ appPickle = \c s -> s{ contents = c ++ contents s }
, appUnPickle = state $ \s -> (contents s, s{ contents = [] })
, theSchema = Any -- XXX
}
-- |All attributes
xpAnyAttrs :: PU HXT.XmlTrees
xpAnyAttrs = PU
{ appPickle = \a s -> s{ attributes = a ++ attributes s }
, appUnPickle = state $ \s -> (attributes s, s{ attributes = [] })
, theSchema = Any -- XXX
}
-- |Any content and attributes: combine 'xpAnyCont' and 'xpAnyAttrs'
xpAny :: PU HXT.XmlTrees
xpAny = (uncurry (++) Inv.:<->: partition XN.isAttr) >$< (xpAnyAttrs >*< xpAnyCont)
-- |Any single element
xpAnyElem :: PU HXT.XmlTree
xpAnyElem = xpWrapEither
( \e -> if XN.isElem e then Right e else Left "xpAnyElem: any element expected"
, id
) xpTree