-- |A set of useful helper functions for dealing with XML data.
module Text.XML.Light.Helpers
 where

import Control.Monad
import Data.Maybe
import Text.XML.Light

-- |Map the given function over the children of the given element with the
-- given name.
mapChildren :: String -> Element -> (Element -> Maybe a) -> Maybe [a]
mapChildren :: String -> Element -> (Element -> Maybe a) -> Maybe [a]
mapChildren s :: String
s e :: Element
e f :: Element -> Maybe a
f = [Maybe a] -> Maybe [a]
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
sequence ([Maybe a] -> Maybe [a]) -> [Maybe a] -> Maybe [a]
forall a b. (a -> b) -> a -> b
$ (Element -> Maybe a) -> [Element] -> [Maybe a]
forall a b. (a -> b) -> [a] -> [b]
map Element -> Maybe a
f ([Element] -> [Maybe a]) -> [Element] -> [Maybe a]
forall a b. (a -> b) -> a -> b
$ QName -> Element -> [Element]
findChildren (String -> QName
unqual String
s) Element
e

-- |Fold the function over the children of the given element with the given
-- name.
foldChildren :: String -> Element -> a -> (a -> Element -> Maybe a) -> Maybe a
foldChildren :: String -> Element -> a -> (a -> Element -> Maybe a) -> Maybe a
foldChildren s :: String
s e :: Element
e b :: a
b f :: a -> Element -> Maybe a
f = (a -> Element -> Maybe a) -> a -> [Element] -> Maybe a
forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m b
foldM a -> Element -> Maybe a
f a
b ([Element] -> Maybe a) -> [Element] -> Maybe a
forall a b. (a -> b) -> a -> b
$ QName -> Element -> [Element]
findChildren (String -> QName
unqual String
s) Element
e

-- |Map the given function over all subelements of the given element with
-- the given name.
mapElements :: String -> Element -> (Element -> Maybe a) -> Maybe [a]
mapElements :: String -> Element -> (Element -> Maybe a) -> Maybe [a]
mapElements s :: String
s e :: Element
e f :: Element -> Maybe a
f = [Maybe a] -> Maybe [a]
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
sequence ([Maybe a] -> Maybe [a]) -> [Maybe a] -> Maybe [a]
forall a b. (a -> b) -> a -> b
$ (Element -> Maybe a) -> [Element] -> [Maybe a]
forall a b. (a -> b) -> [a] -> [b]
map Element -> Maybe a
f ([Element] -> [Maybe a]) -> [Element] -> [Maybe a]
forall a b. (a -> b) -> a -> b
$ QName -> Element -> [Element]
findElements (String -> QName
unqual String
s) Element
e

-- |Fold the given function over the children of the given element with
-- the given name.
foldElements :: String -> Element -> a -> (a -> Element -> Maybe a) -> Maybe a
foldElements :: String -> Element -> a -> (a -> Element -> Maybe a) -> Maybe a
foldElements s :: String
s e :: Element
e b :: a
b f :: a -> Element -> Maybe a
f = (a -> Element -> Maybe a) -> a -> [Element] -> Maybe a
forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m b
foldM a -> Element -> Maybe a
f a
b ([Element] -> Maybe a) -> [Element] -> Maybe a
forall a b. (a -> b) -> a -> b
$ QName -> Element -> [Element]
findElements (String -> QName
unqual String
s) Element
e

--

-- |Map the given function over the children of the given element that
-- have an attribute "name" matching the given string.
mapChildrenWithAttName :: String -> Element -> (Element -> Maybe a) -> Maybe [a]
mapChildrenWithAttName :: String -> Element -> (Element -> Maybe a) -> Maybe [a]
mapChildrenWithAttName s :: String
s e :: Element
e f :: Element -> Maybe a
f = (Element -> Maybe a) -> [Element] -> Maybe [a]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM Element -> Maybe a
f ([Element] -> Maybe [a]) -> [Element] -> Maybe [a]
forall a b. (a -> b) -> a -> b
$ String -> Element -> [Element]
findChildrenWithAttName String
s Element
e

-- |Map the given function over the subelements of the given element that
-- have an attribute "name" matching the given string.
mapElementsWithAttName :: String -> Element -> (Element -> Maybe a) -> Maybe [a]
mapElementsWithAttName :: String -> Element -> (Element -> Maybe a) -> Maybe [a]
mapElementsWithAttName s :: String
s e :: Element
e f :: Element -> Maybe a
f = (Element -> Maybe a) -> [Element] -> Maybe [a]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM Element -> Maybe a
f ([Element] -> Maybe [a]) -> [Element] -> Maybe [a]
forall a b. (a -> b) -> a -> b
$ String -> Element -> [Element]
findElementsWithAttName String
s Element
e

-- |Fold the given function over the children of the given element that
-- have an attribute "name" matching the given string.
foldChildrenWithAttName :: String -> Element -> a ->
                           (a -> Element -> Maybe a) ->
                           Maybe a
foldChildrenWithAttName :: String -> Element -> a -> (a -> Element -> Maybe a) -> Maybe a
foldChildrenWithAttName s :: String
s e :: Element
e b :: a
b f :: a -> Element -> Maybe a
f = (a -> Element -> Maybe a) -> a -> [Element] -> Maybe a
forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m b
foldM a -> Element -> Maybe a
f a
b ([Element] -> Maybe a) -> [Element] -> Maybe a
forall a b. (a -> b) -> a -> b
$ String -> Element -> [Element]
findChildrenWithAttName String
s Element
e

-- |Fold the given function over the subelements of the given element that
-- have an attribute "name" matching the given string.
foldElementsWithAttName :: String -> Element -> a ->
                           (a -> Element -> Maybe a) ->
                           Maybe a
foldElementsWithAttName :: String -> Element -> a -> (a -> Element -> Maybe a) -> Maybe a
foldElementsWithAttName s :: String
s e :: Element
e b :: a
b f :: a -> Element -> Maybe a
f = (a -> Element -> Maybe a) -> a -> [Element] -> Maybe a
forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m b
foldM a -> Element -> Maybe a
f a
b ([Element] -> Maybe a) -> [Element] -> Maybe a
forall a b. (a -> b) -> a -> b
$ String -> Element -> [Element]
findElementsWithAttName String
s Element
e


--

-- |Get the string contents of the child of the given element with the given
-- name.
getChildData :: String -> Element -> Maybe String
getChildData :: String -> Element -> Maybe String
getChildData s :: String
s x :: Element
x = Element -> String
strContent (Element -> String) -> Maybe Element -> Maybe String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` QName -> Element -> Maybe Element
findChild (String -> QName
unqual String
s) Element
x

-- |Get the string contents of the subelement of the given element with the
-- given name.
getElementData :: String -> Element -> Maybe String
getElementData :: String -> Element -> Maybe String
getElementData s :: String
s x :: Element
x = Element -> String
strContent (Element -> String) -> Maybe Element -> Maybe String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` QName -> Element -> Maybe Element
findElement (String -> QName
unqual String
s) Element
x

--

-- |Find a child of the given element with that has an attribute "name"
-- equal to the given string.
findChildWithAttName :: String -> Element -> Maybe Element
findChildWithAttName :: String -> Element -> Maybe Element
findChildWithAttName s :: String
s = [Element] -> Maybe Element
forall a. [a] -> Maybe a
listToMaybe ([Element] -> Maybe Element)
-> (Element -> [Element]) -> Element -> Maybe Element
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Element -> [Element]
findChildrenWithAttName String
s

-- |Find all the children of the given element that have an attribute "name"
-- equal to the given string.
findChildrenWithAttName :: String -> Element -> [Element]
findChildrenWithAttName :: String -> Element -> [Element]
findChildrenWithAttName s :: String
s = (Element -> Bool) -> Element -> [Element]
filterChildren (String -> Element -> Bool
elementHasNameAttr String
s)

-- |Find a subelement of the given element that has an attribute "name"
-- equal to the given string.
findElementWithAttName :: String -> Element -> Maybe Element
findElementWithAttName :: String -> Element -> Maybe Element
findElementWithAttName  s :: String
s = [Element] -> Maybe Element
forall a. [a] -> Maybe a
listToMaybe ([Element] -> Maybe Element)
-> (Element -> [Element]) -> Element -> Maybe Element
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Element -> [Element]
findElementsWithAttName String
s

-- |Find all the subelements of the given element that have an attribute
-- "name" equal to the given string.
findElementsWithAttName :: String -> Element -> [Element]
findElementsWithAttName :: String -> Element -> [Element]
findElementsWithAttName s :: String
s = (Element -> Bool) -> Element -> [Element]
filterElements (String -> Element -> Bool
elementHasNameAttr String
s)

-- |Returns True iff the given alement has an attribute "name" equal to
-- the given string.
elementHasNameAttr :: String -> Element -> Bool
elementHasNameAttr :: String -> Element -> Bool
elementHasNameAttr s :: String
s e :: Element
e =
  case QName -> Element -> Maybe String
findAttr (String -> QName
unqual "name") Element
e of
    Nothing -> Bool
False
    Just v :: String
v  -> String
s String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
v

-- |Convert a list of rows (subelement with the name "row") into a Haskell
-- datatype using the given function.s 
parseRows :: (Element -> Maybe a) -> Element -> Maybe [a]
parseRows :: (Element -> Maybe a) -> Element -> Maybe [a]
parseRows f :: Element -> Maybe a
f xml :: Element
xml = [Maybe a] -> Maybe [a]
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
sequence ([Maybe a] -> Maybe [a]) -> [Maybe a] -> Maybe [a]
forall a b. (a -> b) -> a -> b
$ (Element -> Maybe a) -> [Element] -> [Maybe a]
forall a b. (a -> b) -> [a] -> [b]
map Element -> Maybe a
f ([Element] -> [Maybe a]) -> [Element] -> [Maybe a]
forall a b. (a -> b) -> a -> b
$ QName -> Element -> [Element]
findElements (String -> QName
unqual "row") Element
xml