-- |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