home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / python-support / python-rdflib / rdflib / sparql / graphPattern.py < prev    next >
Encoding:
Python Source  |  2007-04-04  |  13.5 KB  |  362 lines

  1. # -*- coding: utf-8 -*-
  2. #
  3. #
  4. # $Date: 2005/11/04 14:06:36 $, by $Author: ivan $, $Revision: 1.1 $
  5. #
  6. """
  7. Graph pattern class used by the SPARQL implementation
  8. """
  9. import sys, os, time, datetime
  10. from rdflib.Literal     import Literal
  11. from rdflib.BNode       import BNode
  12. from rdflib.URIRef      import URIRef
  13. from types import *
  14.  
  15. from rdflib.sparql import _questChar, Debug, SPARQLError
  16. from rdflib.sparql.Unbound import Unbound
  17.  
  18. def _createResource(v) :
  19.     """Create an RDFLib Literal instance with the corresponding XML
  20.     Schema datatype set. If the variable is already an RDFLib
  21.     resource, it simply returns the resource; otherwise the
  22.     corresponding Literal.  A SPARQLError Exception is raised if the
  23.     type is not implemented.
  24.  
  25.     The Literal contains the string representation of the variable (as
  26.     Python does it by default) with the corresponding XML Schema URI
  27.     set.
  28.  
  29.     @param v: Python variable
  30.     @return: either an RDFLib Literal (if 'v' is not an RDFLib Resource), or the same variable if it is already
  31.     an RDFLib resource (ie, Literal, BNode, or URIRef)
  32.     @raise SPARQLError: if the type of 'v' is not implemented
  33.     """
  34.     if isinstance(v,Literal) or isinstance(v,BNode) or isinstance(v,URIRef) :
  35.         # just do nothing
  36.         return v
  37.     else :
  38.         return Literal(v) # Literal now does the datatype bits
  39.  
  40.  
  41. def _isResQuest(r) :
  42.     """
  43.     Is 'r' a request string (ie, of the form "?XXX")?
  44.  
  45.     @rtype: Boolean
  46.     """
  47.     if r and isinstance(r,basestring) and r[0] == _questChar :
  48.         return True
  49.     return False
  50.  
  51.  
  52. class GraphPattern :
  53.     """
  54.     Storage of one Graph Pattern, ie, the pattern tuples and the
  55.     possible (functional) constraints (filters)
  56.     """
  57.     def __init__(self,patterns=[]) :
  58.         """
  59.         @param patterns: an initial list of graph pattern tuples
  60.         """
  61.         self.patterns    = []
  62.         self.constraints = []
  63.         self.unbounds    = []
  64.         self.bnodes      = {}
  65.         if type(patterns) == list :
  66.             self.addPatterns(patterns)
  67.         elif type(patterns) == tuple :
  68.             self.addPattern(patterns)
  69.         else :
  70.             raise SPARQLError("illegal argument, pattern must be a tuple or a list of tuples")
  71.  
  72.     def _generatePattern(self,tupl) :
  73.         """
  74.         Append a tuple to the local patterns. Possible type literals
  75.         are converted to real literals on the fly.  Each tuple should
  76.         be contain either 3 elements (for an RDF Triplet pattern) or
  77.         four, where the fourth element is a per-pattern constraint
  78.         (filter). (The general constraint of SPARQL can be optimized
  79.         by assigning a constraint to a specific pattern; because it
  80.         stops the graph expansion, its usage might be much more
  81.         optimal than the the 'global' constraint).
  82.  
  83.         @param tupl: either a three or four element tuple
  84.         """
  85.         if type(tupl) != tuple :
  86.             raise SPARQLError("illegal argument, pattern must be a tuple, got %s" % type(tupl))
  87.         if len(tupl) != 3 and len(tupl) != 4 :
  88.             raise SPARQLError("illegal argument, pattern must be a tuple of 3 or 4 element, got %s" % len(tupl))
  89.         if len(tupl) == 3 :
  90.             (s,p,o)   = tupl
  91.             f         = None
  92.         else :
  93.             (s,p,o,f) = tupl
  94.         final=[]
  95.         for c in (s,p,o) :
  96.             if _isResQuest(c) :
  97.                 if not c in self.unbounds :
  98.                     self.unbounds.append(c)
  99.                 final.append(c)
  100.             elif isinstance(c, BNode):
  101.                 #Do nothing - BNode name management is handled by SPARQL parser
  102. #                if not c in self.bnodes :
  103. #                    self.bnodes[c] = BNode()
  104.                 final.append(c)
  105.             else :
  106.                 final.append(_createResource(c))
  107.         final.append(f)
  108.         return tuple(final)
  109.  
  110.     def addPattern(self,tupl) :
  111.         """
  112.         Append a tuple to the local patterns. Possible type literals
  113.         are converted to real literals on the fly.  Each tuple should
  114.         be contain either 3 elements (for an RDF Triplet pattern) or
  115.         four, where the fourth element is a per-pattern constraint
  116.         (filter). (The general constraint of SPARQL can be optimized
  117.         by assigning a constraint to a specific pattern; because it
  118.         stops the graph expansion, its usage might be much more
  119.         optimal than the the 'global' constraint).
  120.  
  121.         @param tupl: either a three or four element tuple
  122.         """
  123.         self.patterns.append(self._generatePattern(tupl))
  124.  
  125.     def insertPattern(self,tupl) :
  126.         """
  127.         Insert a tuple to to the start of local patterns. Possible
  128.         type literals are converted to real literals on the fly.  Each
  129.         tuple should be contain either 3 elements (for an RDF Triplet
  130.         pattern) or four, where the fourth element is a per-pattern
  131.         constraint (filter). (The general constraint of SPARQL can be
  132.         optimized by assigning a constraint to a specific pattern;
  133.         because it stops the graph expansion, its usage might be much
  134.         more optimal than the the 'global' constraint).
  135.  
  136.         Semantically, the behaviour induced by a graphPattern does not
  137.         depend on the order of the patterns. However, due to the
  138.         behaviour of the expansion algorithm, users may control the
  139.         speed somewhat by adding patterns that would 'cut' the
  140.         expansion tree soon (ie, patterns that reduce the available
  141.         triplets significantly). API users may be able to do that,
  142.         hence this additional method.
  143.  
  144.         @param tupl: either a three or four element tuple
  145.         """
  146.         self.patterns.insert(0,self._generatePattern(tupl))
  147.  
  148.  
  149.     def addPatterns(self,lst) :
  150.         """
  151.         Append a list of tuples to the local patterns. Possible type
  152.         literals are converted to real literals on the fly.  Each
  153.         tuple should be contain either three elements (for an RDF
  154.         Triplet pattern) or four, where the fourth element is a
  155.         per-pattern constraint. (The general constraint of SPARQL can
  156.         be optimized by assigning a constraint to a specific pattern;
  157.         because it stops the graph expansion, its usage might be much
  158.         more optimal than the the 'global' constraint).
  159.  
  160.         @param lst: list consisting of either a three or four element tuples
  161.         """
  162.         for l in lst:
  163.             self.addPattern(l)
  164.  
  165.     def insertPatterns(self,lst) :
  166.         """
  167.         Insert a list of tuples to the start of the local
  168.         patterns. Possible type literals are converted to real
  169.         literals on the fly.  Each tuple should be contain either
  170.         three elements (for an RDF Triplet pattern) or four, where the
  171.         fourth element is a per-pattern constraint. (The general
  172.         constraint of SPARQL can be optimized by assigning a
  173.         constraint to a specific pattern; because it stops the graph
  174.         expansion, its usage might be much more optimal than the the
  175.         'global' constraint).
  176.  
  177.         Semantically, the behaviour induced by a graphPattern does not
  178.         depend on the order of the patterns. However, due to the
  179.         behaviour of the expansion algorithm, users may control the
  180.         speed somewhat by adding patterns that would 'cut' the
  181.         expansion tree soon (ie, patterns that reduce the available
  182.         triplets significantly). API users may be able to do that,
  183.         hence this additional method.
  184.  
  185.         @param lst: list consisting of either a three or four element tuples
  186.         """
  187.         for i in xrange(len(lst)-1,-1,-1) :
  188.             self.insertPattern(lst[i])
  189.  
  190.     def addConstraint(self,func) :
  191.         """
  192.         Add a global filter constraint to the graph pattern. 'func'
  193.         must be a method with a single input parameter (a dictionary)
  194.         returning a boolean. This method is I{added} to previously
  195.         added methods, ie, I{all} methods must return True to accept a
  196.         binding.
  197.  
  198.         @param func: filter function
  199.         """
  200.         if type(func) == FunctionType :
  201.             self.constraints.append(func)
  202.         else :
  203.             raise SPARQLError("illegal argument, constraint must be a function type, got %s" % type(func))
  204.  
  205.     def addConstraints(self,lst) :
  206.         """
  207.         Add a list of global filter constraints to the graph
  208.         pattern. Each function in the list must be a method with a
  209.         single input parameter (a dictionary) returning a
  210.         boolean. These methods are I{added} to previously added
  211.         methods, ie, I{all} methods must return True to accept a
  212.         binding.
  213.  
  214.         @param lst: list of functions
  215.         """
  216.         for l in lst:
  217.             self.addConstraint(l)
  218.  
  219.     def construct(self,tripleStore,bindings) :
  220.         """
  221.         Add triples to a tripleStore based on a variable bindings of
  222.         the patterns stored locally.  The triples are patterned by the
  223.         current Graph Pattern. The method is used to construct a graph
  224.         after a successful querying.
  225.  
  226.         @param tripleStore: an (rdflib) Triple Store
  227.         @param bindings: dictionary
  228.         """
  229.         localBnodes = {}
  230.         for c in self.bnodes :
  231.             localBnodes[c] = BNode()
  232.         def bind(st) :
  233.             if _isResQuest(st) :
  234.                 if st in bindings :
  235.                     return bindings[st]
  236.                 else :
  237.                     if isinstance(self,GraphPattern2) :
  238.                         return st
  239.                     else :
  240.                         return None
  241.             elif isinstance(st,BNode) :
  242.                 for c in self.bnodes :
  243.                     if self.bnodes[c] == st :
  244.                         # this is a BNode that was created as part of building up the pattern
  245.                         return localBnodes[c]
  246.                 # if we got here, the BNode comes from somewhere else...
  247.                 return st
  248.             else :
  249.                 return st
  250.  
  251.         for pattern in self.patterns :
  252.             (s,p,o,f) = pattern
  253.             triplet = []
  254.             valid = True
  255.             for res in (s,p,o) :
  256.                 val = bind(res)
  257.                 if val != None :
  258.                     triplet.append(val)
  259.                 else :
  260.                     valid = False
  261.                     break
  262.             if valid :
  263.                 tripleStore.add(tuple(triplet))
  264.  
  265.     def __add__(self,other) :
  266.         """Adding means concatenating all the patterns and filters arrays"""
  267.         retval = GraphPattern()
  268.         retval += self
  269.         retval += other
  270.         return retval
  271.  
  272.     def __iadd__(self,other) :
  273.         """Adding means concatenating all the patterns and filters arrays"""
  274.         self.patterns    += other.patterns
  275.         self.constraints += other.constraints
  276.         for c in other.unbounds :
  277.             if not c in self.unbounds :
  278.                 self.unbounds.append(c)
  279.         for c in other.bnodes :
  280.             if not c in self.bnodes :
  281.                 self.bnodes[c] = other.bnodes[c]
  282.         return self
  283.  
  284.     def __repr__(self) :
  285.         retval  = "   Patterns:    %s\n" % self.patterns
  286.         retval += "   Constraints: %s\n" % self.constraints
  287.         retval += "   Unbounds:    %s\n" % self.unbounds
  288.         return retval
  289.  
  290.     def __str__(self) :
  291.         return self.__repr__()
  292.  
  293.     def isEmpty(self) :
  294.         """Is the pattern empty?
  295.         @rtype: Boolean
  296.         """
  297.         return len(self.patterns) == 0
  298.  
  299.         
  300. class BasicGraphPattern(GraphPattern) :
  301.     """One, justified, problem with the current definition of L{GraphPattern<GraphPattern>} is that it
  302.     makes it difficult for users to use a literal of the type "?XXX", because any string beginning
  303.     with "?" will be considered to be an unbound variable. The only way of doing this is that the user
  304.     explicitly creates a Literal object and uses that as part of the pattern.
  305.  
  306.     This class is a superclass of L{GraphPattern<GraphPattern>} which does I{not} do this, but requires the
  307.     usage of a separate variable class instance"""
  308.  
  309.     def __init__(self,patterns=[]) :
  310.         """
  311.         @param patterns: an initial list of graph pattern tuples
  312.         """
  313.         GraphPattern.__init__(self,patterns)    
  314.     
  315.     def _generatePattern(self,tupl) :
  316.         """
  317.         Append a tuple to the local patterns. Possible type literals
  318.         are converted to real literals on the fly.  Each tuple should
  319.         be contain either 3 elements (for an RDF Triplet pattern) or
  320.         four, where the fourth element is a per-pattern constraint
  321.         (filter). (The general constraint of SPARQL can be optimized
  322.         by assigning a constraint to a specific pattern; because it
  323.         stops the graph expansion, its usage might be much more
  324.         optimal than the the 'global' constraint).
  325.  
  326.         @param tupl: either a three or four element tuple
  327.         """
  328.         if type(tupl) != tuple :
  329.             raise SPARQLError("illegal argument, pattern must be a tuple, got %s" % type(tupl))
  330.         if len(tupl) != 3 and len(tupl) != 4 :
  331.             raise SPARQLError("illegal argument, pattern must be a tuple of 3 or 4 element, got %s" % len(tupl))
  332.         if len(tupl) == 3 :
  333.             (s,p,o)   = tupl
  334.             f         = None
  335.         else :
  336.             (s,p,o,f) = tupl
  337.         final=[]
  338.         for c in (s,p,o) :
  339.             if isinstance(c,Unbound) :
  340.                 if not c.name in self.unbounds :
  341.                     self.unbounds.append(c.name)
  342.                 final.append(c.name)
  343.             elif isinstance(c, BNode):
  344.                 #Do nothing - BNode name management is handled by SPARQL parser
  345.                 final.append(c)
  346.             else :
  347.                 final.append(_createResource(c))
  348.         final.append(f)
  349.         return tuple(final)
  350.         
  351. if __name__ == '__main__' :
  352.     v1 = Unbound("a")
  353.     g = BasicGraphPattern([("a","?b",24),("?r","?c",12345),(v1,"?c",3333)])
  354.     print g
  355.  
  356.  
  357.  
  358.  
  359.  
  360.  
  361.  
  362.