"""SWIPT Query Module - Sean B. Palmer This is a query engine built on top of the newly modularized SWIPT RDF tool. It gagues whether one graph is entailed within another, and if so outputs the result. Usage: python query.py f.n3 q.n3 > out.n3""" import sys import string import re import util import rdfstore import ntriples import swiptql # Declare some constants S, P, O, C = 0, 1, 2, 3 V, T = 0, 1 L, VAL = 0, 1 URI = 'tag:infomesh.net,2001-08-07:URI' LIT = 'tag:infomesh.net,2001-08-07:Literal' ANON = 'tag:infomesh.net,2001-08-07:Anon' VAR = 'tag:infomesh.net,2001-08-07:Var' RC = 'tag:infomesh.net,2001-08-07:RootContext' CONT = 'tag:infomesh.net,2001-08-07:Context' # For extensibility class Query(rdfstore.RDFStore): """Takes in two RDFStores, and works out if one entails the other. For example: x = Query(); x.query(f.quads, q.quads); x.printresult()""" def __init__(self): rdfstore.RDFStore.__init__(self, data=[]) self.fquads = [] # The input file quads (editable) self.qquads = [] # The query file quads (static) self.results = [] # The output results (writable) self.vars = [] # A list of the universal variables (editable) self.match = '' # A match list (writable) self.currentquad = None # The current quad, one of self.fquads (variable) self.queryquad = None # The query quad, one of self.qquads (variable) def queryn(self, fn, qn): f, q = ntriples.NTriples(), swiptql.SWIPTQL() f.parsen(fn); q.parsen(qn) self.query(f.quads, q.quads) def query(self, f, q): print '@prefix : .' print '@prefix rdfs: .' print ':Result rdfs:subClassOf rdfs:Resource .\n' self.fquads, self.qquads = f, q self.prep() def prep(self): self.vars = [] # Clear the variables list for quad in self.qquads: # Get all the quads in the query document, and put the vars into a list for term in quad: do = 1 if term[T] == VAR: for var in self.vars: if term[V] == var[L]: do = None if do: self.vars.append((term[V], 'empty')) fquadscopy = self.fquads[:] self.quadmatch() self.printvars() # This prints out a list of the universal variables if len(self.fquads) != 0 and fquadscopy != self.fquads: self.prep() # If we can continue to query the store, do so! def quadmatch(self): for quad in self.qquads: self.match = '' self.queryquad = quad[:] # Must be a slice copy! if self.queryquad[S][T] == VAR: self.match += 's' if self.queryquad[P][T] == VAR: self.match += 'p' if self.queryquad[O][T] == VAR: self.match += 'o' self.dothetriple() def printvars(self, do=1): """Prints the universal variables store and values as Notation3.""" for var in self.vars: if var[VAL] == 'empty': do = None if do: print '{ ' for var in self.vars: if var[VAL][T] == URI: print '?%s = <%s> .' %(var[L],var[VAL][V]) elif var[VAL][T] == ANON: print '?%s = _:%s .' %(var[L],var[VAL][V]) elif var[VAL][T] == LIT: print '?%s = "%s" .' %(var[L],var[VAL][V]) else: raise 'Unknown type '+str([T])+' for var '+str(var[L]) print '} a :Result .\n' def dothetriple(self): """Do the triple! Do do do do do do do do do, do do do do do do ...""" if self.match == '': self.selfmatchnone() elif self.match == 's': self.selfmatch(a=[S], u=[P, O]) elif self.match == 'p': self.selfmatch(a=[P], u=[S, O]) elif self.match == 'o': self.selfmatch(a=[O], u=[S, P]) elif self.match == 'sp': self.selfmatchtwo(a=[S, P], u=[O]) elif self.match == 'so': self.selfmatchtwo(a=[S, O], u=[P]) elif self.match == 'po': self.selfmatchtwo(a=[P, O], u=[S]) elif self.match == 'spo': self.selfmatchthree() else: raise 'self.match problem: '+self.match def selfmatchnone(self): for cq in self.fquads: self.currentquad = cq; qq = self.queryquad if cq[S] == qq[S] and cq[P] == qq[P] and cq[O] == qq[O]: self.f2q() def selfmatch(self, a=[], u=[]): # a is one term, u is two for cq in self.fquads: self.currentquad = cq; qq = self.queryquad for var in self.vars: if var[L] == qq[a[0]][V] and var[VAL] == 'empty': if cq[u[0]] == qq[u[0]] and cq[u[1]] == qq[u[1]]: self.varsreplace(var[L], cq[a[0]]); self.f2q() elif var[L] == qq[a[0]][V] and var[VAL] != 'empty': self.replacevalinqq(a[0], var[VAL], '1') self.selfmatchnone() def selfmatchtwo(self, a=[], u=[]): # a is two terms, u is one for quad in self.fquads: self.currentquad = quad; qq, cq = self.queryquad, self.currentquad for var in self.vars: if var[L] == qq[a[0]][V] and var[VAL] != 'empty': self.replacevalinqq(a[0], var[VAL], '1') for var in self.vars: if var[L] == qq[a[1]][V] and var[VAL] == 'empty': self.selfmatch(a=[a[1]], u=[a[0], u[0]]) elif var[L] == qq[a[1]][V] and var[VAL] != 'empty': for var in self.vars: if var[L] == qq[a[0]][V] and var[VAL] == 'empty': self.replacevalinqq(a[0], var[VAL], '2') self.selfmatch(a=[a[0]], u=[a[1], u[0]]) elif var[L] == qq[a[0]][V] and var[VAL] == 'empty': if cq[u[0]] == qq[u[0]]: self.varsreplace(var[L], cq[a[0]]) for var in self.vars: if var[L] == qq[a[1]][V] and var[VAL] == 'empty': if cq[u[0]] == qq[u[0]]: self.varsreplace(var[L], cq[a[1]]); self.f2q() def selfmatchthree(self): # This has been compacted a little for quad in self.fquads: self.currentquad = quad; qq, cq = self.queryquad, self.currentquad if self.matchtrue(0, 0, 1): self.selfmatchtwo(a=[S, P], u=[O]) elif self.matchtrue(0, 1, 0): self.selfmatchtwo(a=[S, O], u=[P]) elif self.matchtrue(0, 1, 1): self.selfmatch(a=[S], u=[P, O]) elif self.matchtrue(1, 0, 0): self.selfmatchtwo(a=[P, O], u=[S]) elif self.matchtrue(1, 0, 1): self.selfmatch(a=[P], u=[S, O]) elif self.matchtrue(1, 1, 0): self.selfmatch(a=[O], u=[S, P]) elif var[L] == qq[S][V] and var[VAL] == 'empty': if cq[S] == qq[S]: self.varsreplace(var[L], cq[S]) for var in self.vars: if var[L] == qq[P][V] and var[VAL] == 'empty': if cq[P] == qq[P]: self.varsreplace(var[L], cq[P]) for var in self.vars: if var[L] == qq[O][V] and var[VAL] == 'empty': if cq[O] == qq[O]: self.varsreplace(var[L], cq[O]) self.f2q() def matchtrue(self, sa, sb, sc): x = self.queryquad x0, x1, x2, s0, s1, s2 = x[S][V], x[P][V], x[O][V], None, None, None if sa == 0: s0 = 'empty' if sb == 0: s1 = 'empty' if sc == 0: s2 = 'empty' for var in self.vars: if var[L] == x0 and var[VAL] == s0: if s0 != 'empty': self.replacevalinqq(S, var[VAL]) for var in self.vars: if var[L] == x1 and var[VAL] == s1: if s1 != 'empty': self.replacevalinqq(P, var[VAL]) for var in self.vars: if var[L] == x2 and var[VAL] == s2: if s2 != 'empty': self.replacevalinqq(0, var[VAL]) return 1 else: return 0 else: return 0 else: return 0 def varsreplace(self, label, x): """Replaces label,'empty' with label,x in self.vars""" self.vars.remove((label, 'empty')); self.vars.append((label, x)) def replacevalinqq(self, qq, var, l): self.queryquad[qq] = var def f2q(self): """Moves self.currentquad from self.fquads to self.results""" self.fquads.remove(self.currentquad); self.results.append(self.currentquad) def printresult(self): print self.ntriples(quads=self.results) def run(): q = Query() q.queryn(sys.argv[1], sys.argv[2]) q.printresult() # Main program if __name__ == "__main__": run() # Phew