module Text.XML.Cursor
(
Cursor
, Axis
, fromDocument
, fromNode
, cut
, parent
, CG.precedingSibling
, CG.followingSibling
, child
, node
, CG.preceding
, CG.following
, CG.ancestor
, descendant
, orSelf
, check
, checkNode
, checkElement
, checkName
, anyElement
, element
, laxElement
, content
, attribute
, laxAttribute
, hasAttribute
, attributeIs
, (CG.&|)
, (CG.&/)
, (CG.&//)
, (CG.&.//)
, (CG.$|)
, (CG.$/)
, (CG.$//)
, (CG.$.//)
, (CG.>=>)
, Boolean(..)
, force
, forceM
) where
import Control.Exception (Exception)
import Control.Monad
import Control.Monad.Trans.Resource (MonadThrow, throwM)
import Data.Function (on)
import qualified Data.Map as Map
import Data.Maybe (maybeToList)
import qualified Data.Text as T
import Text.XML
import Text.XML.Cursor.Generic (child, descendant, node, orSelf,
parent)
import qualified Text.XML.Cursor.Generic as CG
type Axis = Cursor -> [Cursor]
class Boolean a where
bool :: a -> Bool
instance Boolean Bool where
bool :: Bool -> Bool
bool = Bool -> Bool
forall a. a -> a
id
instance Boolean [a] where
bool :: [a] -> Bool
bool = Bool -> Bool
not (Bool -> Bool) -> ([a] -> Bool) -> [a] -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null
instance Boolean (Maybe a) where
bool :: Maybe a -> Bool
bool (Just a
_) = Bool
True
bool Maybe a
_ = Bool
False
instance Boolean (Either a b) where
bool :: Either a b -> Bool
bool (Left a
_) = Bool
False
bool (Right b
_) = Bool
True
type Cursor = CG.Cursor Node
cut :: Cursor -> Cursor
cut :: Cursor -> Cursor
cut = Node -> Cursor
fromNode (Node -> Cursor) -> (Cursor -> Node) -> Cursor -> Cursor
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Cursor -> Node
forall node. Cursor node -> node
CG.node
fromDocument :: Document -> Cursor
fromDocument :: Document -> Cursor
fromDocument = Node -> Cursor
fromNode (Node -> Cursor) -> (Document -> Node) -> Document -> Cursor
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Element -> Node
NodeElement (Element -> Node) -> (Document -> Element) -> Document -> Node
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Document -> Element
documentRoot
fromNode :: Node -> Cursor
fromNode :: Node -> Cursor
fromNode =
(Node -> [Node]) -> Node -> Cursor
forall node. (node -> [node]) -> node -> Cursor node
CG.toCursor Node -> [Node]
cs
where
cs :: Node -> [Node]
cs (NodeElement (Element Name
_ Map Name Text
_ [Node]
x)) = [Node]
x
cs Node
_ = []
check :: Boolean b => (Cursor -> b) -> Axis
check :: (Cursor -> b) -> Axis
check Cursor -> b
f Cursor
c = [Cursor
c | b -> Bool
forall a. Boolean a => a -> Bool
bool (b -> Bool) -> b -> Bool
forall a b. (a -> b) -> a -> b
$ Cursor -> b
f Cursor
c]
checkNode :: Boolean b => (Node -> b) -> Axis
checkNode :: (Node -> b) -> Axis
checkNode Node -> b
f = (Cursor -> b) -> Axis
forall b. Boolean b => (Cursor -> b) -> Axis
check (Node -> b
f (Node -> b) -> (Cursor -> Node) -> Cursor -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Cursor -> Node
forall node. Cursor node -> node
node)
checkElement :: Boolean b => (Element -> b) -> Axis
checkElement :: (Element -> b) -> Axis
checkElement Element -> b
f Cursor
c = case Cursor -> Node
forall node. Cursor node -> node
node Cursor
c of
NodeElement Element
e -> [Cursor
c | b -> Bool
forall a. Boolean a => a -> Bool
bool (b -> Bool) -> b -> Bool
forall a b. (a -> b) -> a -> b
$ Element -> b
f Element
e]
Node
_ -> []
checkName :: Boolean b => (Name -> b) -> Axis
checkName :: (Name -> b) -> Axis
checkName Name -> b
f = (Element -> b) -> Axis
forall b. Boolean b => (Element -> b) -> Axis
checkElement (Name -> b
f (Name -> b) -> (Element -> Name) -> Element -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Element -> Name
elementName)
anyElement :: Axis
anyElement :: Axis
anyElement = (Element -> Bool) -> Axis
forall b. Boolean b => (Element -> b) -> Axis
checkElement (Bool -> Element -> Bool
forall a b. a -> b -> a
const Bool
True)
element :: Name -> Axis
element :: Name -> Axis
element Name
n = (Name -> Bool) -> Axis
forall b. Boolean b => (Name -> b) -> Axis
checkName (Name -> Name -> Bool
forall a. Eq a => a -> a -> Bool
== Name
n)
laxElement :: T.Text -> Axis
laxElement :: Text -> Axis
laxElement Text
n = (Name -> Bool) -> Axis
forall b. Boolean b => (Name -> b) -> Axis
checkName ((Text -> Text -> Bool) -> (Text -> Text) -> Text -> Text -> Bool
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
on Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
(==) Text -> Text
T.toCaseFold Text
n (Text -> Bool) -> (Name -> Text) -> Name -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Name -> Text
nameLocalName)
content :: Cursor -> [T.Text]
content :: Cursor -> [Text]
content Cursor
c = case Cursor -> Node
forall node. Cursor node -> node
node Cursor
c of
(NodeContent Text
v) -> [Text
v]
Node
_ -> []
attribute :: Name -> Cursor -> [T.Text]
attribute :: Name -> Cursor -> [Text]
attribute Name
n Cursor
c =
case Cursor -> Node
forall node. Cursor node -> node
node Cursor
c of
NodeElement Element
e -> Maybe Text -> [Text]
forall a. Maybe a -> [a]
maybeToList (Maybe Text -> [Text]) -> Maybe Text -> [Text]
forall a b. (a -> b) -> a -> b
$ Name -> Map Name Text -> Maybe Text
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup Name
n (Map Name Text -> Maybe Text) -> Map Name Text -> Maybe Text
forall a b. (a -> b) -> a -> b
$ Element -> Map Name Text
elementAttributes Element
e
Node
_ -> []
laxAttribute :: T.Text -> Cursor -> [T.Text]
laxAttribute :: Text -> Cursor -> [Text]
laxAttribute Text
n Cursor
c =
case Cursor -> Node
forall node. Cursor node -> node
node Cursor
c of
NodeElement Element
e -> do
(Name
n', Text
v) <- Map Name Text -> [(Name, Text)]
forall k a. Map k a -> [(k, a)]
Map.toList (Map Name Text -> [(Name, Text)])
-> Map Name Text -> [(Name, Text)]
forall a b. (a -> b) -> a -> b
$ Element -> Map Name Text
elementAttributes Element
e
Bool -> [()]
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> [()]) -> Bool -> [()]
forall a b. (a -> b) -> a -> b
$ ((Text -> Text -> Bool) -> (Text -> Text) -> Text -> Text -> Bool
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
on Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
(==) Text -> Text
T.toCaseFold) Text
n (Name -> Text
nameLocalName Name
n')
Text -> [Text]
forall (m :: * -> *) a. Monad m => a -> m a
return Text
v
Node
_ -> []
hasAttribute :: Name -> Axis
hasAttribute :: Name -> Axis
hasAttribute Name
n Cursor
c =
case Cursor -> Node
forall node. Cursor node -> node
node Cursor
c of
NodeElement (Element Name
_ Map Name Text
as [Node]
_) -> [Cursor] -> (Text -> [Cursor]) -> Maybe Text -> [Cursor]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [] ([Cursor] -> Text -> [Cursor]
forall a b. a -> b -> a
const [Cursor
c]) (Maybe Text -> [Cursor]) -> Maybe Text -> [Cursor]
forall a b. (a -> b) -> a -> b
$ Name -> Map Name Text -> Maybe Text
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup Name
n Map Name Text
as
Node
_ -> []
attributeIs :: Name -> T.Text -> Axis
attributeIs :: Name -> Text -> Axis
attributeIs Name
n Text
v Cursor
c =
case Cursor -> Node
forall node. Cursor node -> node
node Cursor
c of
NodeElement (Element Name
_ Map Name Text
as [Node]
_) -> [ Cursor
c | Text -> Maybe Text
forall a. a -> Maybe a
Just Text
v Maybe Text -> Maybe Text -> Bool
forall a. Eq a => a -> a -> Bool
== Name -> Map Name Text -> Maybe Text
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup Name
n Map Name Text
as]
Node
_ -> []
force :: (Exception e, MonadThrow f) => e -> [a] -> f a
force :: e -> [a] -> f a
force e
e [] = e -> f a
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM e
e
force e
_ (a
x:[a]
_) = a -> f a
forall (m :: * -> *) a. Monad m => a -> m a
return a
x
forceM :: (Exception e, MonadThrow f) => e -> [f a] -> f a
forceM :: e -> [f a] -> f a
forceM e
e [] = e -> f a
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM e
e
forceM e
_ (f a
x:[f a]
_) = f a
x