def __init__(self,graph) : """ @param graph: the graph to be modified """ self.lit_to_bnode = {} self.bnode_to_lit = {} self.graph = graph to_be_removed = [] to_be_added = [] for t in self.graph : (subj,pred,obj) = t # This is supposed to be a "proper" graph, so only the obj may be a literal if isinstance(obj,rdflibLiteral) : # In any case, this should be removed: if t not in to_be_removed : to_be_removed.append(t) # Check if a BNode has already been associated with that literal obj_st = _LiteralStructure(obj) found = False for l in self.lit_to_bnode.keys() : if obj_st.lex == l.lex and obj_st.dt == l.dt and obj_st.lang == l.lang : t1 = (subj, pred, self.lit_to_bnode[l]) to_be_added.append(t1) found = True break if found == False : # the bnode has to be created bn = BNode() # store this in the internal administration self.lit_to_bnode[obj_st] = bn self.bnode_to_lit[bn] = obj_st # modify the graph to_be_added.append((subj,pred,bn)) to_be_added.append((bn,type,Literal)) # Furthermore: a plain literal should be identified with a corresponding xsd:string and vice versa, # cf, RDFS Semantics document if obj_st.dt == None and obj_st.lang == None : newLit = rdflibLiteral(obj_st.lex,datatype = ns_xsd["string"]) new_obj_st = _LiteralStructure(newLit) new_obj_st.dt = ns_xsd["string"] bn2 = BNode() self.lit_to_bnode[new_obj_st] = bn2 self.bnode_to_lit[bn2] = new_obj_st to_be_added.append((subj,pred,bn2)) to_be_added.append((bn2,type,Literal)) elif obj_st.dt == ns_xsd["string"] : newLit = rdflibLiteral(obj_st.lex,datatype = None) new_obj_st = _LiteralStructure(obj) new_obj_st.dt = None bn2 = BNode() self.lit_to_bnode[new_obj_st] = bn2 self.bnode_to_lit[bn2] = new_obj_st to_be_added.append((subj,pred,bn2)) to_be_added.append((bn2,type,Literal)) # Do the real modifications self._massageGraph(to_be_removed,to_be_added)
def __init__(self, graph, closure): """ @param graph: the graph to be modified """ self.lit_to_bnode = {} self.bnode_to_lit = {} self.graph = graph to_be_added = set() _add_bnode = partial(add_bnode, self, to_be_added) # This is supposed to be a "proper" graph, so get the triples which # object is a literal. All of them will be removed from graph and # replaced with the ones stored in `to_be_added` variable. to_be_removed = [ t for t in self.graph if isinstance(t[2], rdflibLiteral) ] for t in to_be_removed: (subj, pred, obj) = t # Test the validity of the datatype if obj.datatype: converter = AltXSDToPYTHON.get(obj.datatype, identity) try: converter(text_type(obj)) except ValueError: closure.add_error( "Lexical value of the literal '%s' does not match its datatype (%s)" % (text_type(obj), obj.datatype)) # Check if a BNode has already been associated with that literal obj_st = _LiteralStructure(obj) items = (b for l, b in self.lit_to_bnode.items() if l == obj_st) l_bnode = next(items, None) if l_bnode: to_be_added.add((subj, pred, l_bnode)) else: _add_bnode(subj, pred, obj_st) # Furthermore: a plain literal should be identified with a corresponding xsd:string and vice versa, # cf, RDFS Semantics document if obj_st.dt is None and obj_st.lang is None: newLit = rdflibLiteral(obj_st.lex, datatype=ns_xsd["string"]) new_obj_st = _LiteralStructure(newLit) new_obj_st.dt = ns_xsd["string"] _add_bnode(subj, pred, new_obj_st) elif obj_st.dt == ns_xsd["string"]: newLit = rdflibLiteral(obj_st.lex, datatype=None) new_obj_st = _LiteralStructure(newLit) # new_obj_st = _LiteralStructure(obj) # Was this the correct one, or was this an old bug? new_obj_st.dt = None _add_bnode(subj, pred, new_obj_st) # Do the real modifications self._massageGraph(to_be_removed, to_be_added)
def restore(self) : """ This method is to be invoked at the end of the forward chain processing. It restores literals (whenever possible) to their original self... """ to_be_removed = [] to_be_added = [] for t in self.graph : (subj, pred, obj) = t # The two cases, namely when the literal appears in subject or object positions, should be treated differently if subj in self.bnode_to_lit : # well... there may be to cases here: either this is the original tuple stating that # this bnode is a literal, or it is the result of an inference. In both cases, the tuple must # be removed from the result without any further action if t not in to_be_removed: to_be_removed.append(t) elif obj in self.bnode_to_lit: # This is where the exchange should take place: put back the real literal into the graph, removing the proxy one if t not in to_be_removed: to_be_removed.append(t) # This is an additional thing due to the latest change of literal handling in RDF concepts. # If a literal is an xsd:string then a plain literal is put in its place for the purpose of serialization... lit = self.bnode_to_lit[obj].lit if lit.datatype is not None and lit.datatype == ns_xsd["string"]: lit = rdflibLiteral(str(lit)) to_be_added.append((subj, pred, lit)) # Do the real modifications self._massageGraph(to_be_removed, to_be_added)
def restore(self): """ This method is to be invoked at the end of the forward chain processing. It restores literals (whenever possible) to their original self... """ to_be_removed = set() to_be_added = set() for t in self.graph: (subj, pred, obj) = t # The two cases, namely when the literal appears in subject or object positions, should be treated # differently if subj in self.bnode_to_lit: # well... there may be to cases here: either this is the original tuple stating that # this bnode is a literal, or it is the result of an inference. In both cases, the tuple must # be removed from the result without any further action to_be_removed.add(t) elif obj in self.bnode_to_lit: # This is where the exchange should take place: put back the real literal into the graph, removing the # proxy one to_be_removed.add(t) # This is an additional thing due to the latest change of literal handling in RDF concepts. # If a literal is an xsd:string then a plain literal is put in its place for the purpose of # serialization... lit = self.bnode_to_lit[obj].lit if lit.datatype is not None and lit.datatype == ns_xsd[ "string"]: lit = rdflibLiteral(text_type(lit)) to_be_added.add((subj, pred, lit)) # Do the real modifications self._massageGraph(to_be_removed, to_be_added)
def closure(self): """ Generate the closure the graph. This is the real 'core'. The processing rules store new triples via the separate method :func:`.Core.store_triple` which stores them in the :code:`added_triples` array. If that array is empty at the end of a cycle, it means that the whole process can be stopped. If required, the relevant axiomatic triples are added to the graph before processing in cycles. Similarly the exchange of literals against bnodes is also done in this step (and restored after all cycles are over). """ self.pre_process() # Handling the axiomatic triples. In general, this means adding all tuples in the list that # forwarded, and those include RDF or RDFS. In both cases the relevant parts of the container axioms should also # be added. if self.axioms: self.add_axioms() # Add the datatype axioms, if needed (note that this makes use of the literal proxies, the order of the call # is important! if self.daxioms: self.add_d_axioms() self.flush_stored_triples() # Get first the 'one-time rules', ie, those that do not need an extra round in cycles down the line self.one_time_rules() self.flush_stored_triples() # Go cyclically through all rules until no change happens new_cycle = True cycle_num = 0 while new_cycle: # yes, there was a change, let us go again cycle_num += 1 # DEBUG: print the cycle number out if self._debug: print("----- Cycle #:%d" % cycle_num) # go through all rules, and collect the replies (to see whether any change has been done) # the new triples to be added are collected separately not to interfere with # the current graph yet self.empty_stored_triples() # Execute all the rules; these might fill up the added triples array for t in self.graph: self.rules(t, cycle_num) # Add the tuples to the graph (if necessary, that is). If any new triple has been generated, a new cycle # will be necessary... new_cycle = len(self.added_triples) > 0 for t in self.added_triples: self.graph.add(t) self.post_process() self.flush_stored_triples() # Add possible error messages if self.error_messages: # I am not sure this is the right vocabulary to use for this purpose, but I haven't found anything! # I could, of course, come up with my own, but I am not sure that would be kosher... ERRNS = Namespace("http://www.daml.org/2002/03/agents/agent-ont#") self.graph.bind("err","http://www.daml.org/2002/03/agents/agent-ont#") for m in self.error_messages: message = BNode() self.graph.add((message, rdf_type, ERRNS['ErrorMessage'])) self.graph.add((message, ERRNS['error'], rdflibLiteral(m)))
def closure(self): """ Generate the closure the graph. This is the real 'core'. The processing rules store new triples via the separate method :func:`.Core.store_triple` which stores them in the :code:`added_triples` array. If that array is empty at the end of a cycle, it means that the whole process can be stopped. If required, the relevant axiomatic triples are added to the graph before processing in cycles. Similarly the exchange of literals against bnodes is also done in this step (and restored after all cycles are over). """ self.pre_process() # Handling the axiomatic triples. In general, this means adding all tuples in the list that # forwarded, and those include RDF or RDFS. In both cases the relevant parts of the container axioms should also # be added. if self.axioms: self.add_axioms() # Add the datatype axioms, if needed (note that this makes use of the literal proxies, the order of the call # is important! if self.daxioms: self.add_d_axioms() self.flush_stored_triples() # Get first the 'one-time rules', ie, those that do not need an extra round in cycles down the line self.one_time_rules() self.flush_stored_triples() # Go cyclically through all rules until no change happens new_cycle = True cycle_num = 0 while new_cycle: # yes, there was a change, let us go again cycle_num += 1 # DEBUG: print the cycle number out if self._debug: print("----- Cycle #:%d" % cycle_num) # go through all rules, and collect the replies (to see whether any change has been done) # the new triples to be added are collected separately not to interfere with # the current graph yet self.empty_stored_triples() # Execute all the rules; these might fill up the added triples array for t in self.graph: self.rules(t, cycle_num) # Add the tuples to the graph (if necessary, that is). If any new triple has been generated, a new cycle # will be necessary... new_cycle = len(self.added_triples) > 0 for t in self.added_triples: self.graph.add(t) self.post_process() self.flush_stored_triples() # Add possible error messages if self.error_messages: # I am not sure this is the right vocabulary to use for this purpose, but I haven't found anything! # I could, of course, come up with my own, but I am not sure that would be kosher... ERRNS = Namespace("http://www.daml.org/2002/03/agents/agent-ont#") self.graph.bind("err", "http://www.daml.org/2002/03/agents/agent-ont#") for m in self.error_messages: message = BNode() self.graph.add((message, rdf_type, ERRNS['ErrorMessage'])) self.graph.add((message, ERRNS['error'], rdflibLiteral(m)))
def __init__(self, graph, closure) : """ @param graph: the graph to be modified """ self.lit_to_bnode = {} self.bnode_to_lit = {} self.graph = graph to_be_removed = [] to_be_added = [] for t in self.graph : (subj, pred, obj) = t # This is supposed to be a "proper" graph, so only the obj may be a literal if isinstance(obj, rdflibLiteral): # Test the validity of the datatype if obj.datatype: try: AltXSDToPYTHON[obj.datatype](str(obj)) except ValueError: closure.add_error("Lexical value of the literal '%s' does not match its datatype (%s)" % (str(obj), obj.datatype)) # In any case, this should be removed: if t not in to_be_removed: to_be_removed.append(t) # Check if a BNode has already been associated with that literal obj_st = _LiteralStructure(obj) found = False for l in self.lit_to_bnode.keys() : if obj_st.lex == l.lex and obj_st.dt == l.dt and obj_st.lang == l.lang : t1 = (subj, pred, self.lit_to_bnode[l]) to_be_added.append(t1) found = True break if not found: # the bnode has to be created bn = BNode() # store this in the internal administration self.lit_to_bnode[obj_st] = bn self.bnode_to_lit[bn] = obj_st # modify the graph to_be_added.append((subj, pred, bn)) to_be_added.append((bn, type, Literal)) # Furthermore: a plain literal should be identified with a corresponding xsd:string and vice versa, # cf, RDFS Semantics document if obj_st.dt is None and obj_st.lang is None: newLit = rdflibLiteral(obj_st.lex, datatype=ns_xsd["string"]) new_obj_st = _LiteralStructure(newLit) new_obj_st.dt = ns_xsd["string"] bn2 = BNode() self.lit_to_bnode[new_obj_st] = bn2 self.bnode_to_lit[bn2] = new_obj_st to_be_added.append((subj, pred, bn2)) to_be_added.append((bn2, type, Literal)) elif obj_st.dt == ns_xsd["string"]: newLit = rdflibLiteral(obj_st.lex, datatype=None) new_obj_st = _LiteralStructure(newLit) # new_obj_st = _LiteralStructure(obj) # Was this the correct one, or was this an old bug? new_obj_st.dt = None bn2 = BNode() self.lit_to_bnode[new_obj_st] = bn2 self.bnode_to_lit[bn2] = new_obj_st to_be_added.append((subj, pred, bn2)) to_be_added.append((bn2, type, Literal)) # Do the real modifications self._massageGraph(to_be_removed, to_be_added)
def __init__(self, graph, closure): """ @param graph: the graph to be modified """ self.lit_to_bnode = {} self.bnode_to_lit = {} self.graph = graph to_be_removed = [] to_be_added = [] for t in self.graph: (subj, pred, obj) = t # This is supposed to be a "proper" graph, so only the obj may be a literal if isinstance(obj, rdflibLiteral): # Test the validity of the datatype if obj.datatype: try: converter = AltXSDToPYTHON[obj.datatype] except KeyError: converter = lambda v: v try: converter(text_type(obj)) except ValueError: closure.add_error( "Lexical value of the literal '%s' does not match its datatype (%s)" % (text_type(obj), obj.datatype)) # In any case, this should be removed: if t not in to_be_removed: to_be_removed.append(t) # Check if a BNode has already been associated with that literal obj_st = _LiteralStructure(obj) found = False for l in list(self.lit_to_bnode.keys()): if obj_st.lex == l.lex and obj_st.dt == l.dt and obj_st.lang == l.lang: t1 = (subj, pred, self.lit_to_bnode[l]) to_be_added.append(t1) found = True break if not found: # the bnode has to be created bn = BNode() # store this in the internal administration self.lit_to_bnode[obj_st] = bn self.bnode_to_lit[bn] = obj_st # modify the graph to_be_added.append((subj, pred, bn)) to_be_added.append((bn, type, Literal)) # Furthermore: a plain literal should be identified with a corresponding xsd:string and vice versa, # cf, RDFS Semantics document if obj_st.dt is None and obj_st.lang is None: newLit = rdflibLiteral(obj_st.lex, datatype=ns_xsd["string"]) new_obj_st = _LiteralStructure(newLit) new_obj_st.dt = ns_xsd["string"] bn2 = BNode() self.lit_to_bnode[new_obj_st] = bn2 self.bnode_to_lit[bn2] = new_obj_st to_be_added.append((subj, pred, bn2)) to_be_added.append((bn2, type, Literal)) elif obj_st.dt == ns_xsd["string"]: newLit = rdflibLiteral(obj_st.lex, datatype=None) new_obj_st = _LiteralStructure(newLit) # new_obj_st = _LiteralStructure(obj) # Was this the correct one, or was this an old bug? new_obj_st.dt = None bn2 = BNode() self.lit_to_bnode[new_obj_st] = bn2 self.bnode_to_lit[bn2] = new_obj_st to_be_added.append((subj, pred, bn2)) to_be_added.append((bn2, type, Literal)) # Do the real modifications self._massageGraph(to_be_removed, to_be_added)