{- | Module : SPARQLEval Author : Manuel Ohlendorf Maintainer : Manuel Ohlendorf Stability : experimental Portability: portable Version : The core evaluation function. -} module SPARQLEval (evalQuery) where import Text.XML.HXT.DOM.Util (noDoubles) import SPARQLDataTypes import SPARQLFunctions import RDFDataTypes import List -- | a helper data type, only for internal use data Binding = BT Var RDFTerm | BU Var URI deriving (Show,Eq,Ord) mkTBind :: Var -> RDFTerm -> Binding mkTBind v t = BT v t mkUBind :: Var -> URI -> Binding mkUBind v u = BU v u -- | generates all possible bindings, also returns the triple with the containing binding. This is not needed yet, but -- can neccesary later. substituteOne :: Triple -> TriplePattern -> [(Triple,[Binding])] substituteOne tr@(Triple (Subject a) (Predicate b) (Object c)) (TriplePatN (Subject x) (Predicate y) (Object z)) = if (a == x && b == y && c == z) then [(tr,[])] else [] substituteOne tr@(Triple (Subject a) (Predicate b) (Object c)) (TriplePatN (SubjectVar x) (Predicate y) (Object z)) = if (b == y && c == z) then [(tr,[mkTBind x a])] else [] substituteOne tr@(Triple (Subject a) (Predicate b) (Object c)) (TriplePatN (Subject x) (PredicateVar y) (Object z)) = if (a == x && c == z) then [(tr,[mkUBind y b])] else [] substituteOne tr@(Triple (Subject a) (Predicate b) (Object c)) (TriplePatN (Subject x) (Predicate y) (ObjectVar z)) = if (a == x && b == y) then [(tr,[mkTBind z c])] else [] substituteOne tr@(Triple (Subject a) (Predicate b) (Object c)) (TriplePatN (SubjectVar x) (PredicateVar y) (Object z)) | x == y = if (equalRDFTermURI a b && c == z) then [(tr,[(mkTBind x a),(mkUBind y b)])] else [] | otherwise = if (c == z) then [(tr,[(mkTBind x a),(mkUBind y b)])] else [] substituteOne tr@(Triple (Subject a) (Predicate b) (Object c)) (TriplePatN (SubjectVar x) (Predicate y) (ObjectVar z)) | x == z = if (a == c && b == y) then [(tr,[(mkTBind x a),(mkTBind z c)])] else [] | otherwise = if (b == y) then [(tr,[(mkTBind x a),(mkTBind z c)])] else [] substituteOne tr@(Triple (Subject a) (Predicate b) (Object c)) (TriplePatN (Subject x) (PredicateVar y) (ObjectVar z)) | y == z = if (equalRDFTermURI c b && a == x) then [(tr,[(mkUBind y b),(mkTBind z c)])] else [] | otherwise = if (a == x) then [(tr,[(mkUBind y b),(mkTBind z c)])] else [] substituteOne tr@(Triple (Subject a) (Predicate b) (Object c)) (TriplePatN (SubjectVar x) (PredicateVar y) (ObjectVar z)) | x == y && y == z = if (equalRDFTermURI a b && equalRDFTermURI c b) then [(tr,[(mkTBind x a), (mkUBind y b),(mkTBind z c)])] else [] | x == y = if (equalRDFTermURI a b) then [(tr,[(mkTBind x a), (mkUBind y b),(mkTBind z c)])] else [] | y == z = if (equalRDFTermURI c b) then [(tr,[(mkTBind x a), (mkUBind y b),(mkTBind z c)])] else [] | x == z = if (a == c) then [(tr,[(mkTBind x a), (mkUBind y b),(mkTBind z c)])] else [] | x/=y && y/=z && x/=z = [(tr,[(mkTBind x a), (mkUBind y b),(mkTBind z c)])] | otherwise = [] substituteOne (Triple _ _ _) _ = [] -- different selector functions. getBindings :: [(Triple,[Binding])] -> [[Binding]] getBindings [] = [] getBindings (x:xs) = [snd x] ++ getBindings xs getVarBinding :: Var -> Binding -> [(Either RDFTerm URI)] getVarBinding v (BT a b) = if v==a then [ (Left b)] else [] getVarBinding v (BU a b) = if v==a then [ (Right b)] else [] getVarBindings :: Var -> [Binding] -> [(Either RDFTerm URI)] getVarBindings _ [] = [] getVarBindings v (x:xs) = getVarBinding v x ++ getVarBindings v xs getAllVarBindings :: [Var] -> [Binding] -> [(Var,[(Either RDFTerm URI)])] getAllVarBindings [] _ = [] getAllVarBindings (x:xs) ys = (x,(getVarBindings x ys)) : getAllVarBindings xs ys substitute :: [Triple] -> [TriplePattern] -> [(Triple,[Binding])] substitute [] [] = [] substitute _ [] = [] substitute [] _ = [] substitute (x:xs) ys = concat (map (substituteOne x) ys) ++ substitute xs ys -- | The evaluation function. -- Takes a 'Query' and a 'RDFStore' and generates a list of possible bindings between variables and concrete values. -- If the 'Query' is not in the normalised form, it is normalised before evaluation starts. evalQuery :: Query -> RDFStore -> [(Var,[(Either RDFTerm URI)])] evalQuery Empty _ = [] evalQuery _ [] = [] evalQuery (Query a b ) store = evalQuery (normalizeQuery (Query a b)) store evalQuery (QueryN var tr) store = getAllVarBindings var (concat(getBindings(noDoubles (substitute store tr))))