#!/usr/bin/python """Gofyniad: A Light RDF Query Engine For PlexRDF""" __license__ = 'Copyright (C) 2001 Sean B. Palmer. GNU GPL 2' """ This is a query engine built on top of Aaron Swartz's RDF API. Usage: python gofyniad.py f.n3 q.n3 > out.n3 """ import sys, string, re, copy, os import rdfapi as rdf import ntriples as nt __author__ = 'Sean B. Palmer' __version__ = '$Revision$' __cvsid__ = '$Id$' # Declare some constants S, P, O, Empty = 'subject', 'predicate', 'object', None class Query(rdf.Store): """Takes in two Stores, and queries one against the other.""" def __init__(self): rdf.Store.__init__(self) self.fstore = [] # The input file quads (editable) self.qstore = [] # The query file quads (static) self.results = [] # The output results (writable) self.vars = {} # A dictionary of the universal variables (editable) self.match = '' # A match list (writable) self.matched = 0 # Matched: how many triples have been matched (var) self.CT = None # The current triple, one of self.fstore (var) self.QT = None # The query triple, one of self.qstore (var) def queryn(self, fn, qn): self.qn = qn f, q = nt.parse(open(fn).read()), nt.parse(open(qn).read()) self.query(f.tripleList, q.tripleList) def query(self, f, q): print '@prefix : .' print '@prefix rdfs: .' print ':Result rdfs:subClassOf rdfs:Resource .\n' self.fstore, self.qstore = f, q self.doquery() def doquery(self): self.vars, self.results, self.matched = {}, [], 0 # Reset some stuff for t in self.qstore: # Get all the quads in the query document, and put the vars into a list for term in [t.subject, t.predicate, t.object]: do = 1 if hasattr(term, 'universal'): if self.vars.has_key(term): do = None if do: self.vars[term] = Empty fstorecopy = self.fstore[:] self.triplematch() self.ifmatched() # Now reparse the store q = nt.parse(open(self.qn).read()); self.qstore = q.tripleList if len(self.fstore) != 0 and fstorecopy != self.fstore: self.doquery() # If we can continue to query the store, do so! def ifmatched(self): if self.matched == len(self.qstore): self.printvars() # This prints out a list of the universal variables self.printresult() # This prints out the results of that query def triplematch(self): for triple in self.qstore: self.match = '' self.QT = triple # Used to be a slice[:] copy # self.dobuiltins() if hasattr(self.QT.subject, 'universal'): self.match += 's' if hasattr(self.QT.predicate, 'universal'): self.match += 'p' if hasattr(self.QT.object, 'universal'): self.match += 'o' self.dothetriple() def dobuiltins(self): """Built ins should probably go here.""" pass def printvars(self, do=1): """Prints the universal variables store and values as Notation3.""" for var in self.vars.keys(): if self.vars[var] == Empty: do = None if do: print '{ ' for var in self.vars.keys(): # TODO: Do this properly if hasattr(self.vars[var], 'uri'): print str(var)+' = '+str(self.vars[var].uri)+' .' else: print str(var)+' = '+str(self.vars[var])+' .' 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 ct in self.fstore: self.CT, qt = ct, self.QT if ((ct.subject == qt.subject) and (ct.predicate == qt.predicate) and (ct.object == qt.object)): self.f2q() def selfmatch(self, a=[], u=[]): # a is one term, u is two for ct in self.fstore: self.CT = ct; qt = self.QT for var in self.vars.keys(): if var == getattr(qt, a[0]) and self.vars[var] == Empty: if ((getattr(ct, u[0]) == getattr(qt, u[0])) and (getattr(ct, u[1]) == getattr(qt, u[1]))): self.varsreplace(var, getattr(ct, a[0])); self.f2q() elif var == getattr(qt, a[0]) and self.vars[var] != Empty: self.replacevalinqt(a[0], self.vars[var], '1') self.selfmatchnone() def selfmatchtwo(self, a=[], u=[]): # a is two terms, u is one for triple in self.fstore: self.CT = triple; qt, ct = self.QT, self.CT for var in self.vars.keys(): if var == getattr(qt, a[0]) and self.vars[var] != Empty: self.replacevalinqt(a[0], self.vars[var], '1') for var in self.vars.keys(): if var == getattr(qt, a[1]) and self.vars[var] == Empty: self.selfmatch(a=[a[1]], u=[a[0], u[0]]) elif var == getattr(qt, a[1]) and self.vars[var] != Empty: for var in self.vars.keys(): if var == getattr(qt, a[0]) and self.vars[var] == Empty: self.replacevalinqt(a[0], self.vars[var], '2') self.selfmatch(a=[a[0]], u=[a[1], u[0]]) elif var == getattr(qt, a[0]) and self.vars[var] == Empty: if getattr(ct, u[0]) == getattr(qt, u[0]): self.varsreplace(var, getattr(ct, a[0])) for var in self.vars.keys(): if var == getattr(qt, a[1]) and self.vars[var] == Empty: if getattr(ct, u[0]) == getattr(qt, u[0]): self.varsreplace(var, getattr(ct, a[1])); self.f2q() def selfmatchthree(self): # This has been compacted a little, using matchtrue for triple in self.fstore: self.CT = triple; qt, ct = self.QT, self.CT 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]) else: for var in self.vars.keys(): if var == qt.subject and self.vars[var] == Empty: if ct.subject == qt.subject: self.varsreplace(var, ct.subject) for var in self.vars.keys(): if var == qt.predicate and self.vars[var] == Empty: if ct.predicate == qt.predicate: self.varsreplace(var, ct.predicate) for var in self.vars.keys(): if var == qt.object and self.vars[var] == Empty: if ct.object == qt.object: self.varsreplace(var, ct.object); self.f2q() def matchtrue(self, sa, sb, sc): x = self.QT x0, x1, x2 = x.subject, x.predicate, x.object s0, s1, s2 = None, None, None for x in ((sa, s0), (sb, s1), (sc, s2)): if x[0] == 0: x[2] = Empty for var in self.vars.keys(): if var == x0 and self.vars[var] == s0: if s0 != Empty: self.replacevalinqt(S, self.vars[var]) for var in self.vars.keys(): if var == x1 and self.vars[var] == s1: if s1 != Empty: self.replacevalinqt(P, self.vars[var]) for var in self.vars.keys(): if var == x2 and self.vars[var] == s2: if s2 != Empty: self.replacevalinqt(0, self.vars[var]) 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""" if self.vars[label] == Empty: self.vars[label] = x def replacevalinqt(self, qt, var, l): if qt == S: self.QT.subject = var elif qt == P: self.QT.predicate = var elif qt == O: self.QT.object = var def f2q(self): """Moves self.CT from self.fstore to self.results""" self.fstore.remove(self.CT) self.results.append(self.CT) self.matched = self.matched+1 def printresult(self): x = rdf.Store() x.tripleList = self.results print nt.serialize(x)+'\n' if __name__ == "__main__": q = Query() q.queryn(sys.argv[1], sys.argv[2])