diff options
author | Nicholas Car <nicholas.car@csiro.au> | 2020-04-16 23:19:22 +1000 |
---|---|---|
committer | Nicholas Car <nicholas.car@csiro.au> | 2020-04-16 23:19:22 +1000 |
commit | 56d0d74c6becdfa22a193c98293314bd6ee9dde1 (patch) | |
tree | 6c44e0328ee76bc665e6dc72c8c416a96e64d174 | |
parent | 26710b0bbd8ed9c8c950479f61ae9dec0a504e2e (diff) | |
download | rdflib-issue_1003.tar.gz |
inverted precedence of base: graph wins over adding base to serialize(). Added RDF/XML, TriX & 1/2 TriG (incomplete)issue_1003
-rw-r--r-- | rdflib/graph.py | 21 | ||||
-rw-r--r-- | rdflib/plugins/serializers/rdfxml.py | 10 | ||||
-rw-r--r-- | rdflib/plugins/serializers/trig.py | 8 | ||||
-rw-r--r-- | rdflib/plugins/serializers/trix.py | 6 | ||||
-rw-r--r-- | rdflib/plugins/serializers/turtle.py | 8 | ||||
-rw-r--r-- | test/test_issue1003.py | 95 |
6 files changed, 114 insertions, 34 deletions
diff --git a/rdflib/graph.py b/rdflib/graph.py index a00730ce..9868b097 100644 --- a/rdflib/graph.py +++ b/rdflib/graph.py @@ -954,18 +954,20 @@ class Graph(Node): but "xml", "n3", "turtle", "nt", "pretty-xml", "trix", "trig" and "nquads" are built in. """ - # if a base is set here, use it, else if it was set at graph creation time, use that (self.base) - if base is not None: - self.base = base + # if base is set for the graph use that, if not and a base is given here, use that + if self.base is not None: + base = self.base + else: + pass # i.e. base is set in this method serializer = plugin.get(format, Serializer)(self) if destination is None: stream = BytesIO() - serializer.serialize(stream, base=self.base, encoding=encoding, **args) + serializer.serialize(stream, base=base, encoding=encoding, **args) return stream.getvalue() if hasattr(destination, "write"): stream = destination - serializer.serialize(stream, base=self.base, encoding=encoding, **args) + serializer.serialize(stream, base=base, encoding=encoding, **args) else: location = destination scheme, netloc, path, params, _query, fragment = urlparse(location) @@ -976,7 +978,7 @@ class Graph(Node): return fd, name = tempfile.mkstemp() stream = os.fdopen(fd, "wb") - serializer.serialize(stream, base=self.base, encoding=encoding, **args) + serializer.serialize(stream, base=base, encoding=encoding, **args) stream.close() if hasattr(shutil, "move"): shutil.move(name, path) @@ -1657,13 +1659,13 @@ class Dataset(ConjunctiveGraph): .. versionadded:: 4.0 """ - def __init__(self, store="default", default_union=False): + def __init__(self, store="default", default_union=False, default_graph_base=None): super(Dataset, self).__init__(store=store, identifier=None) if not self.store.graph_aware: raise Exception("DataSet must be backed by a graph-aware store!") self.default_context = Graph( - store=self.store, identifier=DATASET_DEFAULT_GRAPH_ID + store=self.store, identifier=DATASET_DEFAULT_GRAPH_ID, base=default_graph_base ) self.default_union = default_union @@ -1674,7 +1676,7 @@ class Dataset(ConjunctiveGraph): ) return pattern % self.store.__class__.__name__ - def graph(self, identifier=None): + def graph(self, identifier=None, base=None): if identifier is None: from rdflib.term import rdflib_skolem_genid @@ -1684,6 +1686,7 @@ class Dataset(ConjunctiveGraph): identifier = BNode().skolemize() g = self._graph(identifier) + g.base = base self.store.add_graph(g) return g diff --git a/rdflib/plugins/serializers/rdfxml.py b/rdflib/plugins/serializers/rdfxml.py index 631c8fe0..0da1cccd 100644 --- a/rdflib/plugins/serializers/rdfxml.py +++ b/rdflib/plugins/serializers/rdfxml.py @@ -46,7 +46,11 @@ class XMLSerializer(Serializer): yield prefix, namespace def serialize(self, stream, base=None, encoding=None, **args): - self.base = base + # if base is set for the graph use that, if not and a base is given here, use that + if self.store.base is not None: + self.base = self.store.base + else: + self.base = base self.__stream = stream self.__serialized = {} encoding = self.encoding @@ -60,8 +64,8 @@ class XMLSerializer(Serializer): write('<rdf:RDF\n') # If provided, write xml:base attribute for the RDF - if "xml_base" in args: - write(' xml:base="%s"\n' % args['xml_base']) + if self.base: + write(' xml:base="%s"\n' % self.base) # TODO: # assert( # namespaces["http://www.w3.org/1999/02/22-rdf-syntax-ns#"]=='rdf') diff --git a/rdflib/plugins/serializers/trig.py b/rdflib/plugins/serializers/trig.py index 6c05ad75..2cfc2145 100644 --- a/rdflib/plugins/serializers/trig.py +++ b/rdflib/plugins/serializers/trig.py @@ -39,7 +39,7 @@ class TrigSerializer(TurtleSerializer): for triple in context: self.preprocessTriple(triple) - self._contexts[context]=(self.orderSubjects(), self._subjects, self._references) + self._contexts[context] = (self.orderSubjects(), self._subjects, self._references) def reset(self): super(TrigSerializer, self).reset() @@ -49,7 +49,11 @@ class TrigSerializer(TurtleSerializer): spacious=None, **args): self.reset() self.stream = stream - self.base = base + # if base is set for the graph use that, if not and a base is given here, use that + if self.store.base is not None: + self.base = self.store.base + else: + self.base = base if spacious is not None: self._spacious = spacious diff --git a/rdflib/plugins/serializers/trix.py b/rdflib/plugins/serializers/trix.py index fceec6bd..f3477eab 100644 --- a/rdflib/plugins/serializers/trix.py +++ b/rdflib/plugins/serializers/trix.py @@ -29,6 +29,10 @@ class TriXSerializer(Serializer): self.writer = XMLWriter(stream, nm, encoding, extra_ns={"": TRIXNS}) self.writer.push(TRIXNS[u"TriX"]) + if self.store.base: + base = self.store.base + if base is not None: + self.writer.attribute("http://www.w3.org/XML/1998/namespacebase", base) self.writer.namespaces() if isinstance(self.store, ConjunctiveGraph): @@ -44,6 +48,8 @@ class TriXSerializer(Serializer): def _writeGraph(self, graph): self.writer.push(TRIXNS[u"graph"]) + if graph.base: + self.writer.attribute("http://www.w3.org/XML/1998/namespacebase", graph.base) if isinstance(graph.identifier, URIRef): self.writer.element( TRIXNS[u"uri"], content=text_type(graph.identifier)) diff --git a/rdflib/plugins/serializers/turtle.py b/rdflib/plugins/serializers/turtle.py index 63f9da06..b7f50087 100644 --- a/rdflib/plugins/serializers/turtle.py +++ b/rdflib/plugins/serializers/turtle.py @@ -224,8 +224,10 @@ class TurtleSerializer(RecursiveSerializer): spacious=None, **args): self.reset() self.stream = stream - # if base is set here, override previously set base if set at graph init - if base is not None: + # if base is set for the graph use that, if not and a base is given here, use that + if self.store.base is not None: + self.base = self.store.base + else: self.base = base if spacious is not None: @@ -248,6 +250,8 @@ class TurtleSerializer(RecursiveSerializer): self.endDocument() stream.write(b("\n")) + self.base = None + def preprocessTriple(self, triple): super(TurtleSerializer, self).preprocessTriple(triple) for i, node in enumerate(triple): diff --git a/test/test_issue1003.py b/test/test_issue1003.py index 99953ba9..883022a7 100644 --- a/test/test_issue1003.py +++ b/test/test_issue1003.py @@ -1,4 +1,4 @@ -from rdflib import Graph, Literal, Namespace, RDF, URIRef +from rdflib import Graph, Dataset, Literal, Namespace, RDF, URIRef from rdflib.namespace import SKOS, DCTERMS """ @@ -7,10 +7,15 @@ Testing scenarios: 2. base set at graph creation 3. base set at serialization 4. base set at both graph creation & serialization, serialization overrides + 5. multiple serialization side effect checking + 6. checking results for RDF/XML + 7. checking results for N3 + 8. checking results for TriX & TriG """ # variables -base = Namespace("http://example.org/") +base_one = Namespace("http://one.org/") +base_two = Namespace("http://two.org/") title = Literal("Title", lang="en") description = Literal("Test Description", lang="en") creator = URIRef("https://creator.com") @@ -25,34 +30,88 @@ g.bind("dct", DCTERMS) g.bind("skos", SKOS) -# 1. no base set +# 1. no base set for graph, no base set for serialization g1 = Graph() g1 += g # @base should not be in output assert "@base" not in g.serialize(format='turtle').decode("utf-8") -# 2. base set at graph creation -g2 = Graph(base=base) +# 2. base one set for graph, no base set for serialization +g2 = Graph(base=base_one) g2 += g -# @base should be in output -assert "@base" in g2.serialize(format='turtle').decode("utf-8") +# @base should be in output, from Graph (one) +assert "@base <http://one.org/> ." in g2.serialize(format='turtle').decode("utf-8") -# 3. base set at serialization +# 3. no base set for graph, base two set for serialization g3 = Graph() g3 += g -# @base should be in output -assert "@base" in g3.serialize(format='turtle', base=base).decode("utf-8") +# @base should be in output, from serialization (two) +assert "@base <http://two.org/> ." in g3.serialize(format='turtle', base=base_two).decode("utf-8") -# 4. base set at both graph creation & serialization, serialization overrides -g4 = Graph(base=Namespace("http://nothing.com/")) +# 4. base one set for graph, base two set for serialization, Graph one overrides +g4 = Graph(base=base_one) g4 += g +# @base should be in output, from graph (one) +assert "@base <http://one.org/> ." in g4.serialize(format='turtle', base=base_two).decode("utf-8") +# just checking that the serialization setting (two) hasn't snuck through +assert "@base <http://two.org/> ." not in g4.serialize(format='turtle', base=base_two).decode("utf-8") -# @base should be in output and it should be http://example.org/ (graph init copy) -assert "@base <http://nothing.com/>" in g4.serialize(format='turtle').decode("utf-8") -# @base should be in output and it should be http://example.org/, not http://nothing.com/ (serialization overwritten) -assert "@base <http://example.org/>" in g4.serialize(format='turtle', base=base).decode("utf-8") -# just checking that the graph init base isn't sneakily in output -assert "@base <http://nothing.com/>" not in g4.serialize(format='turtle', base=base).decode("utf-8") + +# 5. multiple serialization side effect checking +g5 = Graph() +g5 += g +# @base should be in output, from serialization (two) +assert "@base <http://two.org/> ." in g5.serialize(format='turtle', base=base_two).decode("utf-8") + +# checking for side affects - no base now set for this serialization +# @base should not be in output +assert "@base" not in g5.serialize(format='turtle').decode("utf-8") + + +# 6. checking results for RDF/XML +g6 = Graph() +g6 += g +g6.bind("dct", DCTERMS) +g6.bind("skos", SKOS) +assert "@xml:base" not in g6.serialize(format='xml').decode("utf-8") +assert 'xml:base="http://one.org/"' in g6.serialize(format='xml', base=base_one).decode("utf-8") +g6.base = base_two +assert 'xml:base="http://two.org/"' in g6.serialize(format='xml').decode("utf-8") +assert 'xml:base="http://two.org/"' in g6.serialize(format='xml', base=base_one).decode("utf-8") + +# 7. checking results for N3 +g7 = Graph() +g7 += g +g7.bind("dct", DCTERMS) +g7.bind("skos", SKOS) +assert "@xml:base" not in g7.serialize(format='xml').decode("utf-8") +assert "@base <http://one.org/> ." in g7.serialize(format='n3', base=base_one).decode("utf-8") +g7.base = base_two +assert "@base <http://two.org/> ." in g7.serialize(format='n3').decode("utf-8") +assert "@base <http://two.org/> ." in g7.serialize(format='n3', base=base_one).decode("utf-8") + +# 8. checking results for TriX & TriG +# TriX can specify a base per graph but setting a base for the whole +base_three = Namespace("http://three.org/") +ds1 = Dataset() +ds1.bind("dct", DCTERMS) +ds1.bind("skos", SKOS) +g8 = ds1.graph(URIRef('http://g8.com/'), base=base_one) +g9 = ds1.graph(URIRef('http://g9.com/')) +g8 += g +g9 += g +g9.base = base_two +ds1.base = base_three + +trix = ds1.serialize(format='trix', base=Namespace("http://two.org/")).decode("utf-8") +assert '<graph xml:base="http://one.org/">' in trix +assert '<graph xml:base="http://two.org/">' in trix +assert '<TriX xml:base="http://three.org/"' in trix + +trig = ds1.serialize(format='trig', base=Namespace("http://two.org/")).decode("utf-8") +assert '@base <http://one.org/> .' not in trig +assert '@base <http://two.org/> .' not in trig +assert '@base <http://three.org/> .' in trig |