summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Car <nicholas.car@csiro.au>2020-03-13 21:16:15 +1000
committerNicholas Car <nicholas.car@csiro.au>2020-03-13 21:16:15 +1000
commita7863d25dc47730f4ef8bdca91c4e35c7f7b1ccf (patch)
treec123e33a55b7c24db9ad93daf59729c7087958d7
parent0e5efef78702575e4abff4d8076eac4e2bd9d5f0 (diff)
downloadrdflib-a7863d25dc47730f4ef8bdca91c4e35c7f7b1ccf.tar.gz
adds cbd() function to Graph() and tests and dependency on black
-rw-r--r--rdflib/graph.py38
-rw-r--r--requirements.txt1
-rw-r--r--test/test_graph_cbd.py63
3 files changed, 102 insertions, 0 deletions
diff --git a/rdflib/graph.py b/rdflib/graph.py
index 4a27e6de..eb0a556e 100644
--- a/rdflib/graph.py
+++ b/rdflib/graph.py
@@ -1269,6 +1269,44 @@ class Graph(Node):
return retval
+ def cbd(self, resource):
+ """Retrieves the Concise Bounded Description of a Resource from a Graph
+
+ Concise Bounded Description (CBD) is defined in [1] as:
+
+ Given a particular node (the starting node) in a particular RDF graph (the source graph), a subgraph of that
+ particular graph, taken to comprise a concise bounded description of the resource denoted by the starting node,
+ can be identified as follows:
+
+ 1. Include in the subgraph all statements in the source graph where the subject of the statement is the
+ starting node;
+ 2. Recursively, for all statements identified in the subgraph thus far having a blank node object, include
+ in the subgraph all statements in the source graph where the subject of the statement is the blank node
+ in question and which are not already included in the subgraph.
+ 3. Recursively, for all statements included in the subgraph thus far, for all reifications of each statement
+ in the source graph, include the concise bounded description beginning from the rdf:Statement node of
+ each reification.
+
+ This results in a subgraph where the object nodes are either URI references, literals, or blank nodes not
+ serving as the subject of any statement in the graph.
+
+ [1] https://www.w3.org/Submission/CBD/
+
+ :param resource: a URIRef object, of the Resource for queried for
+ :return: a Graph, subgraph of self
+ """
+ subgraph = Graph()
+
+ def add_to_cbd(uri):
+ for s, p, o in self.triples((uri, None, None)):
+ subgraph.add((s, p, o))
+ # recurse 'down' through ll Blank Nodes
+ if type(o) == BNode and not (o, None, None) in subgraph:
+ add_to_cbd(o)
+ add_to_cbd(resource)
+
+ return subgraph
+
class ConjunctiveGraph(Graph):
diff --git a/requirements.txt b/requirements.txt
index 215e257a..28129288 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -5,3 +5,4 @@ pyparsing
requests
six
doctest-ignore-unicode
+black
diff --git a/test/test_graph_cbd.py b/test/test_graph_cbd.py
new file mode 100644
index 00000000..88adf8be
--- /dev/null
+++ b/test/test_graph_cbd.py
@@ -0,0 +1,63 @@
+import unittest
+from rdflib import Graph, Namespace
+
+
+class CbdTestCase(unittest.TestCase):
+ """Tests the Graph class' cbd() function"""
+
+ def setUp(self):
+ self.g = Graph()
+ # adding example data for testing
+ self.g.parse(
+ data="""PREFIX ex: <http://ex/>
+ PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
+
+ ex:R1
+ a rdf:Resource ;
+ ex:hasChild ex:R2 , ex:R3 .
+
+ ex:R2
+ ex:propOne ex:P1 ;
+ ex:propTwo ex:P2 .
+
+ ex:R3
+ ex:propOne ex:P3 ;
+ ex:propTwo ex:P4 ;
+ ex:propThree [
+ a rdf:Resource ;
+ ex:propFour "Some Literal" ;
+ ex:propFive ex:P5 ;
+ ex:propSix [
+ ex:propSeven ex:P7 ;
+ ] ;
+ ] .
+ """,
+ format="turtle",
+ )
+
+ self.EX = Namespace("http://ex/")
+ self.g.bind("ex", self.EX)
+
+ def testCbd(self):
+ self.assertEqual(
+ len(self.g.cbd(self.EX.R1)), 3, "cbd() for R1 should return 3 triples"
+ )
+
+ self.assertEqual(
+ len(self.g.cbd(self.EX.R2)), 2, "cbd() for R3 should return 2 triples"
+ )
+
+ self.assertEqual(
+ len(self.g.cbd(self.EX.R3)), 8, "cbd() for R3 should return 8 triples"
+ )
+
+ self.assertEqual(
+ len(self.g.cbd(self.EX.R4)), 0, "cbd() for R4 should return 0 triples"
+ )
+
+ def tearDown(self):
+ self.g.close()
+
+
+if __name__ == "__main__":
+ unittest.main()