#!/usr/bin/python """Eep RDF API: Built-Ins""" __author__ = 'Sean B. Palmer' __license__ = 'Copyright (C) 2002 Sean B. Palmer. GNU GPL 2' # import eep, query, infer from eep3 import api, query eep = api import copy, cwmclone DAML_first = eep.Article('') DAML_rest = eep.Article('') DAML_nil = eep.Article('') nslist, builtins = [], {} # Register the namespaces def regns(ns): if ns not in nslist: nslist.append(ns) return ns LOG_NS = regns('http://www.w3.org/2000/10/swap/log#') STRING_NS = regns('http://www.w3.org/2000/10/swap/string#') UTIL_NS = regns('http://example.org/#') # Create the builtins # L o g i c B u i l t - I n s class BI_log_equalTo: def evaluate(self, t): return (`t[0]` == `t[2]`) class BI_log_notEqualTo: def evaluate(self, t): return (`t[0]` != `t[2]`) class BI_log_uri: def evaluateObject(self, t, blist=None): if t[0].type == 'URI': t = t[:] return [t[0], t[1], eep.Article('"'+t[0].value+'"')], None else: return 1, None class BI_log_racine: def evaluateObject(self, t, blist=None): if t[0].type == 'URI': t = t[:] if '#' in t[0].value: t[2] = eep.Article('<'+t[0][0:(t[0].value.find('#'))]+'>') return [t[0], t[1], t[2]], None else: return 1, None class BI_log_content: def evaluateObject(self, t, blist=None): import urllib2 if t[0].type == 'URI': t = t[:] try: content = urllib2.urlopen(t[0].value).read() except: content = 'Error getting URI' return [t[0], t[1], eep.Article('"'+content+'"')], None else: return 1, None # S t r i n g B u i l t - I n s class BI_string_notEqualTo: def evaluate(self, t): if (t[0].type != 'Literal') or (t[2].type != 'Literal'): return 0 else: return (t[0].value != t[2].value) class BI_string_startsWith: def evaluate(self, t): if (t[0].type != 'Literal') or (t[2].type != 'Literal'): return 0 elif (t[0].value[:len(t[2].value)] == t[2].value): return 1 else: return 0 class BI_string_concat: def evaluateObject(self, t, blist=None): t = t[:] x = cwmclone.getList({None: blist}, t[0]) for triple in x: if triple.type == 'Univar': return 'not yet', None y = '"'+''.join([a.value for a in x])+'"' return [t[0], t[1], eep.Article(y)], None class BI_string_split: def evaluateObject(self, t, blist=None): t = t[:] x = cwmclone.getList({None: blist}, t[0]) for triple in x: if triple.type == 'Univar': return 'not yet', None str, spl = x[0].value, x[1].value bits = [eep.Article('"'+x+'"') for x in str.split(spl)] list = cwmclone.genID() result = [t[0], t[1], list] extra = cwmclone.makeList(bits) return result, extra # U t i l i t y B u i l t - I n s class BI_util_sha512: def evaluateObject(self, t, blist=None): import sha512 if t[0].type == 'Literal': t = t[:] try: x = sha512.new(t[0].value).hexdigest() except: x = 'Built in failed gently: SHA module problem' return [t[0], t[1], eep.Article('"%s"' % x)], None else: return 1, None class BI_util_rawType: def evaluateObject(self, t, blist=None): t = t[:] t2 = eep.Article('"'+t[0].type+'"') return [t[0], t[1], t2], None # Register the builtins def register(c, ns, name): builtins[ns+name] = c register(BI_log_equalTo, LOG_NS, 'equalTo') register(BI_log_notEqualTo, LOG_NS, 'notEqualTo') register(BI_log_uri, LOG_NS, 'uri') register(BI_log_racine, LOG_NS, 'racine') register(BI_log_content, LOG_NS, 'content') register(BI_string_notEqualTo, STRING_NS, 'notEqualTo') register(BI_string_startsWith, STRING_NS, 'startsWith') register(BI_string_concat, STRING_NS, 'concat') register(BI_string_split, STRING_NS, 'split') register(BI_util_sha512, UTIL_NS, 'sha512') register(BI_util_rawType, UTIL_NS, 'rawType') # Other stuff def isBI(t): """Tests for a triple using a built-in predicate. This is optimized so that it shouldn't slow down queries too much.""" if t[1].type != 'URI': return 0 do = 0 for ns in nslist: if t[1].value[:len(ns)] == ns: do = 1 if not do: return 0 if t[1].value not in builtins.keys(): return 0 return 1 def bi(t, blist=[]): if (t[0].type == 'Univar') and (t[2].type == 'Univar'): return t, None elif (t[0].type == 'Univar') and (t[2].type != 'Univar'): return builtins[t[1].value]().evaluateSubject(t, blist) elif (t[0].type != 'Univar') and (t[2].type == 'Univar'): return builtins[t[1].value]().evaluateObject(t, blist) elif (t[0].type != 'Univar') and (t[2].type != 'Univar'): if builtins[t[1].value]().evaluate(t): return 1, None else: return 0, None def doBuiltIns(queue, bdict, resultDict, blists=[]): """ newbins is a list of built-ins that were taken out before the query. bdict is a list of variables that need to be satisfied in the builtins, and res is the query result. We need to iteratively match the builtins until no more variables are added. Sometimes, we will try to satisfy the variables in a builtin which can only take one thingy. That needs to be resolved. """ TYPE, VAL, subj, pred, obj = 0, 1, 0, 1, 2 DEBUG = 0 # If the query didn't find all of the material needed, then the query fails if None in resultDict.values(): raise "Query not fully satisfied" # For each value in the result dict, add it to the bdict. All values in the # bdict need to be satisfied for the builtins to have passed, and the # builtins need to have passed, of course. for var in resultDict.keys(): # var is a `Univar` if var in bdict.keys(): bdict[var] = resultDict[var] if DEBUG: print 'resultDict:::', resultDict if DEBUG: print 'bdict:::', bdict queue = [list(item) for item in queue] # hack! # Bung in the initial variables from the resultDict for item in queue: # item is a built-in triple to do for pos in (0, 1, 2): if ((item[pos].type == 'Univar') and (`item[pos]` in resultDict.keys())): bdict[`item[pos]`] = eep.Article(resultDict[`item[pos]`]) item[pos] = eep.Article(resultDict[`item[pos]`]) # Put some of the existing variables into the bdict for triple in blists: for pos in (0, 1, 2): if ((triple[pos].type == 'Univar') and (`triple[pos]` not in bdict.keys())): bdict[`triple[pos]`] = None # Transfer more bindings over for v in resultDict.keys(): if (v in bdict.keys()): if bdict[v] is None: bdict[v] = resultDict[v] for i in range(len(blists)): for pos in (0, 1, 2): if ((blists[i][pos].type == 'Univar') and bdict[`blists[i][pos]`]): t = list(blists[i]) new = bdict[`blists[i][pos]`] t[pos] = eep.Article(new) blists._triples[`t[1]`][`t[0]`] = [new] blists[i] = t if DEBUG: print 'queue:::', queue # Now we put the BI types in each member of the queue for i in range(len(queue)): done = 0 for funcname in dir(builtins[queue[i][pred].value]()): if funcname[:8] == 'evaluate': queue[i], done = [funcname, queue[i]], 1 if not done: raise "No evaluate in "+builtins[queue[i][pred].value] if DEBUG: print 'queue:::', queue # Now we need to keep doing builtins for each thing in the queue. We only # stop when * the queue has had all of its BIs done * the queue has not # had any updates in the last iteration # By update, we mean that there are no variables left to satisfy, or truths # to check done = [] # list of builtins that we've done ext = [] # list of extra stuff # The following block tests for the type of builtin, and if everything # matches, performs the builtin while 1: qlen, dlen = len(queue), len(done) for biToDo in queue: # subst in any new values for pos in (0, 1, 2): if ((biToDo[VAL][pos].type == 'Univar') and bdict[`biToDo[VAL][pos]`]): biToDo[VAL][pos] = eep.Article(bdict[`biToDo[VAL][pos]`]) for i in range(len(blists)): for pos in (0, 1, 2): if ((blists[i][pos].type == 'Univar') and bdict[`blists[i][pos]`]): t = list(blists[i]) new = bdict[`blists[i][pos]`] t[pos] = eep.Article(new) blists._triples[`t[1]`][`t[0]`] = [new] blists[i] = t if DEBUG: print biToDo[TYPE], biToDo[VAL][subj].type, biToDo[VAL][obj].type if ((biToDo[TYPE] == 'evaluate') and (biToDo[VAL][subj].type != 'Univar') and (biToDo[VAL][obj].type != 'Univar')): biResult = bi(biToDo[VAL], blists) elif ((biToDo[TYPE] == 'evaluateSubject') and (biToDo[VAL][subj].type == 'Univar') and (biToDo[VAL][obj].type != 'Univar')): biResult = bi(biToDo[VAL], blists) elif ((biToDo[TYPE] == 'evaluateObject') and (biToDo[VAL][subj].type != 'Univar') and (biToDo[VAL][obj].type == 'Univar')): biResult = bi(biToDo[VAL], blists) else: biResult = ('not yet', None) if DEBUG: print 'biResult:::', biResult biResult, extras = biResult[0], biResult[1] if biResult == 0: # builtin failed. Go home if DEBUG: print 'Removing because false: '+str(biToDo) queue.remove(biToDo) done.append(0) elif biResult not in (1, 'not yet'): # A list. May have vars, which we need to sub. for pos in (0, 1, 2): if biToDo[VAL][pos].type == 'Univar': bdict[`biToDo[VAL][pos]`] = biResult[pos] biToDo[VAL][pos] = biResult[pos] queue.remove(biToDo) done.append(biToDo[VAL]) elif biResult != 'not yet': # i.e. it equals 1 if DEBUG: print 'Removing because true: '+str(biToDo) queue.remove(biToDo) # we did it. No new vars else: pass if extras: ext.extend(extras) print 'done', done if DEBUG: print 'biToDo - done:::', biToDo[VAL] # we've done it once for all items in the queue if (len(queue) == 0) or (not len(done) > dlen): break if DEBUG: print 'done!:::', queue, done if (len(queue) > 0) or (0 in done): # still stuff on the queue? bork! return bdict, [0], ext else: return bdict, done, ext def bfilter(store, r, formula=None): blist = api.TripleStore() desc = r[1] ante = eep.TripleStore(filter(lambda t: not isBI(t), r[0])) bins = eep.TripleStore(filter(lambda t: isBI(t), r[0])) # Make a dictionary of the vars in the builtins bd = {} for triple in bins: for pos in (0, 1, 2): if triple[pos].type[-3:] == 'var': bd[`triple[pos]`] = None # find all lists that belong in bins for triple in bins: for article in triple: if cwmclone.isList({None: ante}, article): blist = cwmclone.getList({None: ante}, article, all=1) for triple in blist: ante = ante.remove(triple) qres, result = query.query(store[formula], ante), [] for res in qres: newbins, bdict = [triple[:] for triple in bins], copy.copy(bd) bdict, int, extras = doBuiltIns(newbins, bdict, res[1], blist) # @@ # print 'b, i, e', bdict, int, extras if len(int) > 0: if int[0] == 0: int = [0] else: int = [] for t in desc: t = list(t[:]) for p in (0, 1, 2): if (t[p].type == 'Univar') and (`t[p]` in res[1].keys()): t[p] = eep.Article(res[1][`t[p]`]) elif (t[p].type == 'Univar') and (`t[p]` in bdict.keys()): t[p] = eep.Article(bdict[`t[p]`]) int.append(t) int.extend(extras) if len(int) > 0: if int[0] != 0: result.append(int) else: result.append(int) return result if __name__=="__main__": print __doc__