TableAlgebra-0.7.1: src/Database/Ferry/Algebra/Render/XMLUtils.hs
module Database.Ferry.Algebra.Render.XMLUtils where
import Text.XML.HaXml.Types
import Database.Ferry.Algebra.Data.Algebra
import qualified Data.Map as M
import Control.Monad.State
import Control.Monad.Writer
import Control.Monad.Reader
-- Convenient alias for column names
type ColName = String
-- The Graph is represented as a tuple of an int, that represents the first node, and
-- a list of algebraic nodes with their node numbers.
type Graph = (AlgNode, [(Algebra, AlgNode)])
-- Alias for GraphNode ids
type GraphNode = Int
-- Alias for xmlNode ids
type XMLNode = Int
-- Mapping from graphnodes to xmlnode ids. This dictionary is used to prevent duplicate xml nodes
type Dictionary = M.Map GraphNode XMLNode
-- XML monad, all elements are printed in bottom up!!! order into the writer monad so
-- that the xml can easily be printed an will be accepted by pfopt.
-- The reader monad contains the map with all the nodes from the algebraic plan, the keys
-- are the node ids from the graph. The state monad keeps track of the supply of fresh ids
-- for xml nodes and the dictionary for looking up whether a certain graphnode already has
-- an xml representation.
type XML = WriterT [Element ()] (ReaderT (M.Map AlgNode Algebra, M.Map AlgNode [String], Bool) (State (Int, Dictionary)))
getTags :: GraphNode -> XML (Maybe [String])
getTags i = do
(_, ts, _) <- ask
return $ M.lookup i ts
-- Debug enabled?
debugEnabled :: XML Bool
debugEnabled = do
(_,_,d) <- ask
return d
-- Has a graphnode already been translated into an xml node. If yes which node?
isDefined :: GraphNode -> XML (Maybe XMLNode)
isDefined g = do
(_, d) <- get
return $ M.lookup g d
-- Get a fresh xml node id.
freshId :: XML Int
freshId = do
(n, d) <- get
put (n + 1, d)
return n
-- Add a mapping from a graphnode to an xml node id to the dictionary
addNodeTrans :: GraphNode -> XMLNode -> XML ()
addNodeTrans gId xId = do
(n, d) <- get
put (n, M.insert gId xId d)
-- Get a node from the algebraic plan with a certain graphNode id number
getNode :: Int -> XML Algebra
getNode i = do
(nodes, _, _) <- ask
return $ nodes M.! i
-- Run the monad and return a list of xml elements from the monad.
runXML :: Bool -> M.Map AlgNode Algebra -> M.Map AlgNode [String] -> XML a -> [Element ()]
runXML debug m t = snd . fst . flip runState (0, M.empty) . flip runReaderT (m, t, debug) . runWriterT
-- * Helper functions for constructing xml nodes
infixr 0 `childsOf`
infixr 0 `dataChildOf`
infixr 0 `attrsOf`
-- | Childs of takes a list of xml elements, and nests them in the xml element given as a second argument
childsOf :: [Element ()] -> Element () -> Element ()
childsOf cs (Elem n attrs cs') = Elem n attrs $ cs' ++ [CElem c () | c <- cs]
-- | Data child of takes some data that can be printed and adds that as child to the xml element given as second argument
dataChildOf :: Show a => a -> Element () -> Element ()
dataChildOf v (Elem n attrs cs) = Elem n attrs $ (CString False (show v) ()) : cs
stringChildOf :: String -> Element () -> Element ()
stringChildOf v (Elem n attrs cs) = Elem n attrs $ (CString False v ()) : cs
-- | Construct a column with name n, and new status v
column :: String -> Bool -> Element ()
column n v = let new = case v of
True -> "true"
False -> "false"
in [attr "name" n, attr "new" new] `attrsOf` xmlElem "column"
-- | XML element representing a type
typeN :: ATy -> Element ()
typeN t = [attr "name" $ show t] `attrsOf` xmlElem "type"
-- | Construct an xml tag with name n
xmlElem :: String -> Element ()
xmlElem n = Elem (N n) [] []
-- | Construct an algebraic node with id xId and of kind t
node :: XMLNode -> String -> Element ()
node xId t = [attr "id" $ show xId, attr "kind" t] `attrsOf` xmlElem "node"
-- | Construct a content node
contentNode :: Element ()
contentNode = xmlElem "content"
-- | Construct an attribute for an xml node, attrname = n and its value is v
attr :: String -> String -> Attribute
attr n v = (N n, AttValue [Left v])
-- | Attach list of attributes to an xml element
attrsOf :: [Attribute] -> Element () -> Element ()
attrsOf at (Elem n attrs cs) = Elem n (at ++ attrs) cs