RDFLib/rdflib — Issue #142: Namespaces beginning with _ are invalid
Author: gjhiggins
Created: 2012-02-20 08:33:42+00:00
State: open

wwai...@gmail.com, 2010-11-26T22:53:44.000Z

The NamespaceManager will invent namespace prefixes when its
compute_qname method is called. The prefixes it invents start with
an underscore. The legality of this might be debated but there are
several parsers, amongst them redland, that cannot read N3/turtle
generated by rdflib because of this unless inordinate care is taken
that all possible prefixes be defined beforehand.

The fix below copies the behaviour of Virtuoso which invents prefixes
starting with "ns" and a number.

Patch below

---

diff --git a/rdflib/namespace.py b/rdflib/namespace.py
index 935f1a1..127a854 100644
--- a/rdflib/namespace.py
+++ b/rdflib/namespace.py
@@ -191,7 +191,12 @@ class NamespaceManager(object):
namespace = URIRef(namespace)
prefix = self.store.prefix(namespace)
if prefix is None:
- prefix = "_%s" % len(list(self.store.namespaces()))
+ num = 1
+ while 1:
+ prefix = "ns%s" % num
+ if not self.store.namespace(prefix):
+ break
+ num += 1
self.bind(prefix, namespace)
self.__cache[uri] = (prefix, namespace, name)
return self.__cache[uri]
diff --git a/test/test_namespace.py b/test/test_namespace.py
new file mode 100644
index 0000000..4aba036
--- /dev/null
+++ b/test/test_namespace.py
@@ -0,0 +1,17 @@
+from rdflib.graph import Graph
+from rdflib.term import URIRef
+
+def test_qname():
+ """Test sequential assignment of unknown prefixes"""
+ g = Graph()
+ assert g.compute_qname(URIRef("http://foo/bar/baz")) == \
+ ("ns1", URIRef("http://foo/bar/"), "baz")
+
+ assert g.compute_qname(URIRef("http://foo/bar#baz")) == \
+ ("ns2", URIRef("http://foo/bar#"), "baz")
+
+ # should skip this because we already assign it
+ g.bind("ns3", URIRef("http://exampe.org/"))
+
+ assert g.compute_qname(URIRef("http://blip/blop")) == \
+ ("ns4", URIRef("http://blip/"), "blop")

Comment 1 by ed.summers
Can you attach the output of `svn diff` to this ticket please? It will make applying the patch a lot easier.

Comment 2 by wwai...@gmail.com
As an attachment... It should apply with 'patch -p1 < qname_prefix.diff'

Comment 3 by ed.summers

Comment 4 by ed.summers

Comment 5 by ed.summers
I guess we can chalk this up to a difference between Turtle and N3. Turtle is a subset of N3. So what is valid N3 isn't necessarily valid Turtle. In this case N3 allows prefixes to start with a underscore, and Turtle does not. And redland understands Turtle, whereas rdflib understands N3 :-)

That being said I think it makes sense to encourage a bit more interoperability between redland and rdflib by making the change you suggest:

>>> g = rdflib.Graph()
>>> g.add((rdflib.URIRef('http://example.com/foo'), rdflib.URIRef('http://example.com/bar'), rdflib.Literal(1)))
>>> print g.serialize(format='n3')
@prefix _3: .

_3:bar 1

will become:

>>> g = rdflib.Graph()
>>> g.add((rdflib.URIRef('http://example.com/foo'), rdflib.URIRef('http://example.com/bar'), rdflib.Literal(1)))
>>> g.serialize(format='n3')
'@prefix ns1: .\n@prefix ns2: .\n\nns1:foo ns1:bar 1 .\n\n'
>>> print g.serialize(format='n3')
@prefix ns1: .
@prefix ns2: .

ns1:foo ns1:bar 1 .

It's interesting that the subject and object URIs becomes prefixed after this change. I wonder if that could potentially end up blowing up the number of prefixes used when serializing as N3?

Comment 6 by ed.summers
I'm not sure this "blowing up" of prefixes demonstrated in test.py (attached) is good for large graphs:

before patch:

% ./test.py

a .

a .

a .

a .

a .

a .

a .

a .

a .

after patch:

% ./test.py
@prefix ns1: .
@prefix ns10: .
@prefix ns2: .
@prefix ns3: .
@prefix ns4: .
@prefix ns5: .
@prefix ns6: .
@prefix ns7: .
@prefix ns8: .
@prefix ns9: .

ns6:i a ns2:Person .

ns8:i a ns2:Person .

ns4:i a ns2:Person .

ns3:i a ns2:Person .

ns1:i a ns2:Person .

ns5:i a ns2:Person .

ns7:i a ns2:Person .

ns9:i a ns2:Person .

ns10:i a ns2:Person .

Comment 7 by wwai...@gmail.com
attached patch modifies the turtle serialiser to prevent prefix explosion...

Comment 9 by ed.summers
I'm just realizing now that the Turtle serializer emits the prefix with a leading underscore...so this really is a defect.

Comment 10 by ed.summers
This issue was closed by revision r1899.

Comment 11 by ed.summers
This issue was closed by revision dcea99e96edc.