diff options
| author | Nicholas Car <nicholas.car@csiro.au> | 2020-03-13 21:16:15 +1000 |
|---|---|---|
| committer | Nicholas Car <nicholas.car@csiro.au> | 2020-03-13 21:16:15 +1000 |
| commit | a7863d25dc47730f4ef8bdca91c4e35c7f7b1ccf (patch) | |
| tree | c123e33a55b7c24db9ad93daf59729c7087958d7 | |
| parent | 0e5efef78702575e4abff4d8076eac4e2bd9d5f0 (diff) | |
| download | rdflib-a7863d25dc47730f4ef8bdca91c4e35c7f7b1ccf.tar.gz | |
adds cbd() function to Graph() and tests and dependency on black
| -rw-r--r-- | rdflib/graph.py | 38 | ||||
| -rw-r--r-- | requirements.txt | 1 | ||||
| -rw-r--r-- | test/test_graph_cbd.py | 63 |
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() |
