Viewing file: sparqlOperators.py (15.64 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
# -*- coding: utf-8 -*- # # # $Date: 2005/11/04 14:06:36 $, by $Author: ivan $, $Revision: 1.1 $ # ## # API for the SPARQL operators. The operators (eg, 'lt') # return a <em>function</em> that can be added to the AND clause of a query. The parameters are either regular values # or query strings. The resulting function has one parameter (the binding directory), it can be combined with others or # be plugged to into an array of constraints. For example: # <pre> # constraints = [lt("?m",42)] #</pre> # <p>for checking whether "?m" is smaller than the (integer) value 42. It can be combined using the lambda function, for # example:</p> # <pre> # constraints = [lambda(b) : lt("?m",42")(b) or lt("?n",134)(b)] # </pre> # <p>is the expression for:</p> # <pre> # AND ?m < 42 || ?n < 134 # </pre> # <p>(Clearly, the relative complexity is only on the API level; a SPARQL language parser that starts with a SPARQL # expression can map on this API).</p> # ##
import sys, os, re from rdflib.Literal import Literal, _XSD_NS from rdflib.BNode import BNode from rdflib.URIRef import URIRef from rdflib import Variable from rdflib.sparql.graphPattern import _createResource from rdflib.sparql import _questChar, Debug
## # Boolean test whether this is a a query string or not # @param v the value to be checked # @return True if it is a query string def queryString(v) : return isinstance(v,basestring) and len(v) != 0 and v[0] == _questChar
## # Return the value in a literal, making on the fly conversion on datatype (using the datatypes that are implemented) # @param v the Literal to be converted # @return the result of the conversion. def getLiteralValue(v) : return v
## # Returns a <em>value retrieval function</em>. The return value can be plugged in a query; it would return # the value of param directly if param is a real value, and the run-time value if param is a query string of the type # "?xxx". If no binding is defined at the time of call, the return value is None # @param param query string, Unbound instance, or real value # @return a function taking one parameter (the binding directory) def getValue(param) : if isinstance(param,Variable) : unBound = True else : unBound = queryString(param) if not unBound : if isinstance(param,Literal) : value = getLiteralValue(param) elif callable(param): return param else : value = param return lambda(bindings): value def f(bindings) : if unBound : #@@note, param must be reassigned to avoid tricky issues of scope #see: http://docs.python.org/ref/naming.html _param = isinstance(param,Variable) and param or Variable(param[1:]) val = bindings[_param] if isinstance(val,Literal) : return getLiteralValue(val) else : return val else : return value return f
## # Operator for '<' # @param a value or query string # @param b value or query string # @return comparison method def lt(a,b) : fa = getValue(a) fb = getValue(b) def f(bindings) : try : return fa(bindings) < fb(bindings) except: # raise # this is the case when the operators are incompatible if Debug : (typ,val,traceback) = sys.exc_info() sys.excepthook(typ,val,traceback) return False return f
## # Operator for '<=' # @param a value or query string # @param b value or query string # @return comparison method def le(a,b) : fa = getValue(a) fb = getValue(b) def f(bindings) : try : return fa(bindings) <= fb(bindings) except : # this is the case when the operators are incompatible if Debug : (typ,val,traceback) = sys.exc_info() sys.excepthook(typ,val,traceback) return False return f
## # Operator for '>' # @param a value or query string # @param b value or query string # @return comparison method def gt(a,b) : fa = getValue(a) fb = getValue(b) def f(bindings) : try : return fa(bindings) > fb(bindings) except : # this is the case when the operators are incompatible if Debug : (typ,val,traceback) = sys.exc_info() sys.excepthook(typ,val,traceback) return False return f
## # Operator for '>=' # @param a value or query string # @param b value or query string # @return comparison method def ge(a,b) : fa = getValue(a) fb = getValue(b) def f(bindings) : try : return fa(bindings) >= fb(bindings) except : # this is the case when the operators are incompatible if Debug : (typ,val,traceback) = sys.exc_info() sys.excepthook(typ,val,traceback) return False return f
## # Operator for '=' # @param a value or query string # @param b value or query string # @return comparison method def eq(a,b) : fa = getValue(a) fb = getValue(b) def f(bindings) : try : return fa(bindings) == fb(bindings) except : # this is the case when the operators are incompatible if Debug : (typ,val,traceback) = sys.exc_info() sys.excepthook(typ,val,traceback) return False return f ## # Operator for '!=' # @param a value or query string # @param b value or query string # @return comparison method def neq(a,b) : fa = getValue(a) fb = getValue(b) def f(bindings) : try : return fa(bindings) != fb(bindings) except : # this is the case when the operators are incompatible if Debug : (typ,val,traceback) = sys.exc_info() sys.excepthook(typ,val,traceback) return False return f
def __getVariableName(v): if isinstance(v, Variable): return v elif queryString(v): return v[1:] else: return None
## # Is the variable bound # @param a value or query string # @return check method def bound(a) : v = __getVariableName(a) def f(bindings) : if v == None : return False if v in bindings : val = bindings[v] return not (val == None) else : return False return f
## # Is the variable bound to a URIRef # @param a value or query string # @return check method def isURI(a) : v = __getVariableName(a) def f(bindings) : if v == None : return False try : val = bindings[v] if val == None: return False else : return isinstance(val,URIRef) except : return False return f
## # Is the variable bound to a IRIRef (this is just an alias for URIRef) # @param a value or query string # @return check method def isIRI(a) : return isURI(a)
## # Is the variable bound to a Blank Node # @param a value or query string # @return check method def isBlank(a) : v = __getVariableName(a) def f(bindings) : if v == None : return False try : val = bindings[v] if val == None: return False else : return isinstance(val,BNode) except : return False return f
## # Is the variable bound to a Literal # @param a value or query string # @return check method def isLiteral(a) : v = __getVariableName(a) def f(bindings) : if v == None : return False try : val = bindings[v] if val == None: return False else : return isinstance(val,Literal) except : return False return f
## # Return the string version of a resource # @param a value or query string # @return check method def str(a) : v = __getVariableName(a) def f(bindings) : if v == None : return "" try : val = bindings[v] if val == None: return "" else : from __builtin__ import str as _str return _str(val) except : return "" return f
## # Return the lang value of a literal # @param a value or query string # @return check method def lang(a) : v = __getVariableName(a) def f(bindings) : if v == None: return "" try : val = bindings[v] if val == None: return "" else : return val.language except : return "" return f
## # Return the datatype URI of a literal # @param a value or query string # @return check method def datatype(a) : v = __getVariableName(a) def f(bindings) : if v == None: if isinstance(a,Literal): return a.datatype else: raise TypeError(a)
try : val = bindings[v] if val == None: return TypeError(v) elif isinstance(val,Literal) and not val.language: return val.datatype else: raise TypeError(val) except : raise TypeError(v) return f
## # Is a resource on a collection. The operator can be used to check whether # the 'item' is an element of the 'collection' (a.k.a. list). Both collection and item can # be a real resource or a query string. # @param collection is either a query string (that has to be bound by the query) or an RDFLib Resource # representing the collection # @param item is either a query string (that has to be bound by the query), an RDFLib Resource, or # a data type value that is turned into a corresponding Literal (with possible datatype) # that must be tested to be part of the collection # @defreturn a function def isOnCollection(collection,item, triplets) : """Generate a method that can be used as a global constaint in sparql to check whether the 'item' is an element of the 'collection' (a.k.a. list). Both collection and item can be a real resource or a query string. Furthermore, item might be a plain string, that is then turned into a literal run-time. The method returns an adapted method. """ #check_subject(collection) collUnbound = False if isinstance(collection,Variable) : collUnbound = True collection = collection elif queryString(collection) : # just keep 'collection', no reason to reassign collUnbound = True else: collUnbound = False # if we got here, this is a valid collection resource if isinstance(item,Variable) : queryItem = item itUnbund = True elif queryString(item) : queryItem = item itUnbound = True else : # Note that an exception is raised if the 'item' is invalid queryItem = _createResource(item) itUnbound = False def checkCollection(bindings) : try : if collUnbound == True : # the binding should come from the binding coll = bindings[collection] else : coll = collection if itUnbound == True : it = bindings[queryItem] else : it = queryItem return it in triplets.items(coll) except : # this means that the binding is not available. But that also means that # the global constraint was used, for example, with the optional triplets; # not available binding means that the method is irrelevant for those # ie, it should not become a show-stopper, hence it returns True return True return checkCollection
def addOperator(args,combinationArg): """ SPARQL numeric + operator implemented via Python """ return ' + '.join(["sparqlOperators.getValue(%s)%s"%(i,combinationArg and "(%s)"%combinationArg or '') for i in args])
def XSDCast(source,target=None): """ XSD Casting/Construction Support For now (this may be an issue since Literal doesn't override comparisons) it simply creates a Literal with the target datatype using the 'lexical' value of the source """ sFunc = getValue(source) def f(bindings): rt = sFunc(bindings) if isinstance(rt,Literal) and rt.datatype == target: #Literal already has target datatype return rt else: return Literal(rt,datatype=target) return f
def regex(item,pattern,flag=None): """ Invokes the XPath fn:matches function to match text against a regular expression pattern. The regular expression language is defined in XQuery 1.0 and XPath 2.0 Functions and Operators section 7.6.1 Regular Expression Syntax """ a = getValue(item) b = getValue(pattern) if flag: cFlag = 0 usedFlags = [] #Maps XPath REGEX flags (http://www.w3.org/TR/xpath-functions/#flags) to Python's re flags for fChar,_flag in [('i',re.IGNORECASE),('s',re.DOTALL),('m',re.MULTILINE)]: if fChar in flag and fChar not in usedFlags: cFlag |= _flag usedFlags.append(fChar) def f1(bindings): try: return bool(re.compile(b(bindings),cFlag).search(a(bindings))) except: return False return f1 else: def f2(bindings): try: return bool(re.compile(b(bindings)).search(a(bindings))) except: return False return f2
def f(bindings): try: return bool(re.compile(a(bindings)).search(b(bindings))) except Exception,e: print e return False return f
def EBV(a): """ * If the argument is a typed literal with a datatype of xsd:boolean, the EBV is the value of that argument. * If the argument is a plain literal or a typed literal with a datatype of xsd:string, the EBV is false if the operand value has zero length; otherwise the EBV is true. * If the argument is a numeric type or a typed literal with a datatype derived from a numeric type, the EBV is false if the operand value is NaN or is numerically equal to zero; otherwise the EBV is true. * All other arguments, including unbound arguments, produce a type error. """ fa = getValue(a) def f(bindings) : try : rt = fa(bindings) if isinstance(rt,Literal): if rt.datatype == _XSD_NS.boolean: ebv = rt.toPython() elif rt.datatype == _XSD_NS.string or rt.datatype is None: ebv = len(rt) > 0 else: pyRT = rt.toPython() if isinstance(pyRT,Literal): #Type error, see: http://www.w3.org/TR/rdf-sparql-query/#ebv raise TypeError("http://www.w3.org/TR/rdf-sparql-query/#ebv") else: ebv = pyRT != 0 return ebv else: print rt, type(rt) raise except Exception,e: if isinstance(e,KeyError): #see: http://www.w3.org/TR/rdf-sparql-query/#ebv raise TypeError("http://www.w3.org/TR/rdf-sparql-query/#ebv") # this is the case when the operators are incompatible raise if Debug : (typ,val,traceback) = sys.exc_info() sys.excepthook(typ,val,traceback) return False return f
|