RDFLib/rdflib — Issue #123: Suggested method on Graph for BNode Closure
Author: gjhiggins
Created: 2012-02-20 08:33:16+00:00
State: open

wwai...@gmail.com, 2010-07-22T16:05:40.000Z

def bnc(self, triple, *av, **kw):
"""
Return the BNode closure(s) for triples that are matched
by the given "triple". Any additional positional or keyword
arguments are passed to the constructor for the new graph.
"""
result = Graph(*av, **kw)
for s,p,o in self.triples(triple):
result.add((s,p,o))
if isinstance(o, BNode):
result += self.bnc((o, None, None))
return result

Comment 1 by wwai...@gmail.com
Supporting methods:

def one(self, triple):
"""
Return one matching "triple" or "None"
"""
for statement in self.triples(triple):
return statement

def exists(self, triple):
"""
Return "True" if "triple" exists in the graph, "False" otherwise
"""
statement = self.one(triple)
if statement is not None:
return True
return False

Comment 2 by wwai...@gmail.com
improved original function that won't loop in case of silly bnode loops (thanks gromgull):

def bnc(self, triple, *av, **kw):
"""
Return the BNode closure(s) for triples that are matched
by the given "triple". Any additional positional or keyword
arguments are passed to the constructor for the new graph.
"""
result = Graph(*av, **kw)
for s,p,o in self.triples(triple):
result.add((s,p,o))
if isinstance(o, BNode) and not result.exists((o, None, None)):
result += self.bnc((o, None, None))
return result

Comment 3 by wwai...@gmail.com
This code comes from:

http://knowledgeforge.net/pdw/ordf/file/tip/ordf/graph.py

Comment 4 by vfaronov
Graphs support the `in` operator, so `exists` is unnecessary, I believe.

Comment 5 by drewpca
one() should raise an exception instead of returning None. The functionality is the same either way (though the exception can include a helpful message), but with None, every caller is obligated to check the type of the output. Forgetting to do so will lead to TypeErrors later on (when someone tries to unpack the None value).

'bnc' should have a descriptive name, possibly 'bnode_closure' or 'bnode_closure_graph'. Why doesn't a subject (or predicate) bnode cause recursion? (None, FOAF.name, Literal("Drew")) might be the IFP that I use to find a person, and wouldn't bnode_closure be the right way to get the other triples about that person? If I'm getting the use case wrong, please revise the docstring to explain why only objects are checked for BNode.