hxt-9.1.0: src/Data/Tree/NavigatableTree/XPathAxis.hs
-- ------------------------------------------------------------
{- |
Module : Data.Tree.NavigatableTree.XPathAxis
Copyright : Copyright (C) 2010 Uwe Schmidt
License : MIT
Maintainer : Uwe Schmidt (uwe\@fh-wedel.de)
Stability : experimental
Portability: portable
Navigatable trees need to have operations to move up, down, left and right.
With these elementary operations, the XPath axises can be defined.
-}
-- ------------------------------------------------------------
module Data.Tree.NavigatableTree.XPathAxis
where
import Data.Maybe ( maybeToList )
import Data.Tree.NavigatableTree.Class
import Control.Arrow ( (>>>) )
import Control.Monad ( (>=>) )
-- ------------------------------------------------------------
--
-- mothers little helpers
-- | collect all trees by moving into one direction, starting tree is included
maybeStar :: (a -> Maybe a) -> (a -> [a])
maybeStar f x = x : maybe [] (maybeStar f) (f x)
-- | collect all trees by moving into one direction, starting tree is not included
maybePlus :: (a -> Maybe a) -> (a -> [a])
maybePlus f x = maybe [] (maybeStar f) (f x)
{-# INLINE maybePlus #-}
-- ------------------------------------------------------------
-- XPath axis
-- | XPath axis: parent
parentAxis :: NavigatableTree t => t a -> [t a]
parentAxis = maybeToList . mvUp
{-# INLINE parentAxis #-}
-- | XPath axis: ancestor
ancestorAxis :: NavigatableTree t => t a -> [t a]
ancestorAxis = maybePlus mvUp
{-# INLINE ancestorAxis #-}
-- | XPath axis: ancestor or self
ancestorOrSelfAxis :: NavigatableTree t => t a -> [t a]
ancestorOrSelfAxis = maybeStar mvUp
{-# INLINE ancestorOrSelfAxis #-}
-- | XPath axis: child
childAxis :: NavigatableTree t => t a -> [t a]
childAxis = (mvDown >>> maybeToList) >=> maybeStar mvRight
{-# INLINE childAxis #-}
-- | XPath axis: descendant
descendantAxis :: NavigatableTree t => t a -> [t a]
descendantAxis = descendantOrSelfAxis >>> tail
{-# INLINE descendantAxis #-}
-- | XPath axis: descendant or self
descendantOrSelfAxis :: NavigatableTree t => t a -> [t a]
descendantOrSelfAxis = visit []
where
visit k t = t : maybe k (visit' k) (mvDown t)
visit' k t = visit (maybe k (visit' k) (mvRight t)) t
-- | not an official XPath axis but useful: reverse descendant or self, used in preceding axis
revDescendantOrSelfAxis :: NavigatableTree t => t a -> [t a]
revDescendantOrSelfAxis t
= t : concatMap revDescendantOrSelfAxis (reverse $ childAxis t)
-- | XPath axis: following sibling
followingSiblingAxis :: NavigatableTree t => t a -> [t a]
followingSiblingAxis = maybePlus mvRight
{-# INLINE followingSiblingAxis #-}
-- | XPath axis: preceeding sibling
precedingSiblingAxis :: NavigatableTree t => t a -> [t a]
precedingSiblingAxis = maybePlus mvLeft
{-# INLINE precedingSiblingAxis #-}
-- | XPath axis: self
selfAxis :: NavigatableTree t => t a -> [t a]
selfAxis = (:[])
{-# INLINE selfAxis #-}
-- | XPath axis: following
followingAxis :: NavigatableTree t => t a -> [t a]
followingAxis = ancestorOrSelfAxis >=> followingSiblingAxis >=> descendantOrSelfAxis
-- | XPath axis: preceding
precedingAxis :: NavigatableTree t => t a -> [t a]
precedingAxis = ancestorOrSelfAxis >=> precedingSiblingAxis >=> revDescendantOrSelfAxis
-- | move to the root
mvToRoot :: NavigatableTree t => t a -> t a
mvToRoot = ancestorOrSelfAxis >>> last
{-# INLINE mvToRoot #-}
isAtRoot :: NavigatableTree t => t a -> Bool
isAtRoot = null . ancestorAxis
{-# INLINE isAtRoot #-}
-- ------------------------------------------------------------