dom-parser-0.1.0: src/Text/XML/DOM/Parser/Class.hs
module Text.XML.DOM.Parser.Class
( -- * FromDom
FromDom(..)
, proxyFromDom
-- * Explicit methods for convenience
, elementFromDom
, unionFromDom
, textFromDom
, stringFromDom
, charFromDom
, intFromDom
, integerFromDom
, doubleFromDom
, fixedFromDom
, boolFromDom
, unitFromDom
, voidFromDom
) where
import Control.Applicative
import Control.Lens
import Data.Fixed
import Data.OpenUnion
import Data.Text (Text)
import qualified Data.Text as T
import Data.Typeable
import Data.Void
import Text.Shakespeare.Text (st)
import Text.XML
import Text.XML.DOM.Parser.Combinators
import Text.XML.DOM.Parser.Types
import TypeFun.Data.List hiding (Union)
proxyFromDom
:: forall proxy m a
. (FromDom a, Monad m)
=> proxy a
-> DomParserT Identity m a
proxyFromDom _ = fromDom
-- | Class of types which can be parsed from single XML element.
class FromDom a where
fromDom :: (Monad m) => DomParserT Identity m a
instance FromDom () where
fromDom = unitFromDom
instance FromDom Void where
fromDom = voidFromDom
instance FromDom Text where
fromDom = textFromDom
instance FromDom String where
fromDom = stringFromDom
instance FromDom Char where
fromDom = charFromDom
instance FromDom Int where
fromDom = intFromDom
instance FromDom Integer where
fromDom = integerFromDom
instance FromDom Double where
fromDom = doubleFromDom
instance (HasResolution a, Typeable a) => FromDom (Fixed a) where
fromDom = fixedFromDom
instance FromDom Bool where
fromDom = boolFromDom
instance FromDom (Union '[]) where
fromDom = empty
instance ( Typeable a, FromDom a, FromDom (Union as)
, SubList as (a ': as) )
=> FromDom (Union (a ': as)) where
-- fromDom :: forall m. (DomParserMonad m) => m a
fromDom = (liftUnion <$> (proxyFromDom (Proxy :: Proxy a)))
<|> (reUnion <$> (proxyFromDom (Proxy :: Proxy (Union as))))
instance FromDom Element where
fromDom = elementFromDom
elementFromDom :: (Monad m) => DomParserT Identity m Element
elementFromDom = view $ pdElements . to runIdentity
unionFromDom
:: (Monad m, FromDom (Union as))
=> proxy as
-> DomParserT Identity m (Union as)
unionFromDom _ = fromDom
textFromDom :: (Monad m) => DomParserT Identity m Text
textFromDom = parseContent pure
stringFromDom :: (Monad m) => DomParserT Identity m String
stringFromDom = parseContent $ pure . T.unpack
charFromDom :: (Monad m) => DomParserT Identity m Char
charFromDom = parseContent $ \t -> case T.unpack $ T.strip t of
[c] -> pure c
_ -> throwParserError $ PEWrongFormat
"Should have exactly one non-blank character"
intFromDom :: (Monad m) => DomParserT Identity m Int
intFromDom = parseContent readContent
integerFromDom :: (Monad m) => DomParserT Identity m Integer
integerFromDom = parseContent readContent
doubleFromDom :: (Monad m) => DomParserT Identity m Double
doubleFromDom = parseContent readContent
fixedFromDom
:: (Monad m, Typeable a, HasResolution a)
=> DomParserT Identity m (Fixed a)
fixedFromDom = parseContent readContent
-- | Expects content to be y, yes, t, true or 1 for True value. n, no,
-- f, false or 0 for False value. Case is not significant, blank
-- characters are striped.
boolFromDom :: (Monad m) => DomParserT Identity m Bool
boolFromDom = parseContent $ \t ->
let
lowt = T.toLower $ T.strip t
tvals = ["y", "yes", "t", "true", "1"]
fvals = ["n", "no", "f", "false", "0"]
in if | lowt `elem` tvals -> return True
| lowt `elem` fvals -> return False
| otherwise ->
let msg = [st|Could not read "#{t}" as Bool|]
in throwParserError $ PEWrongFormat msg
-- | Always successfully parses any DOM to @()@
unitFromDom :: (Monad m) => DomParserT Identity m ()
unitFromDom = pure ()
-- | Never parses successfully. It is just 'mzero'
voidFromDom :: (Monad m) => DomParserT Identity m Void
voidFromDom = empty