packages feed

hxt-7.1: doc/cookbook/SPARQLEval.hs

{- |
   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))))