Jena tip: namespaces and the j.0 problem
A frequently asked question we get on the Jena list is paraphrased as: “help -
my output contains these weird j.0
namespaces, how do I get rid of them?”. In
the hope that Google will save some future askers of this question some time,
here’s an explanation of what is happening, and what to do about it.
First, consider the following code snippet:
public static void main( String\[\] args ) {
Model m = ModelFactory.createDefaultModel();
Property p = m.createProperty( "p" );
Resource r = m.createResource( "r" );
r.addProperty( p, 42 );
m.write( System.out, "RDF/XML" );
}
This could be expected to write a representation of the simple RDF model
r p "42"
. But in fact, it produces a Java exception. Exactly which exception
depends on the version of Jena we are using, in my current test setup I get
Exception in thread "main" com.hp.hpl.jena.rdf.arp.RelativeURIException: No
scheme found in URI 'p'
. The problem is that RDF (and RDFS, and OWL) expect
the names of things to be URI’s. The symbol p
isn’t a URI. So let’s change
the example slightly:
public static void main( String\[\] args ) {
Model m = ModelFactory.createDefaultModel();
String NS = "http://example.com/foo#";
Property p = m.createProperty( NS + "p" );
Resource r = m.createResource( NS + "r" );
r.addProperty( p, 42 );
m.write( System.out, "RDF/XML" );
}
OK, now this runs and produces the following output:
<rdf:RDF
xmlns:j.0="http://example.com/foo#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" >
<rdf:Description rdf:about="http://example.com/foo#r">
<j.0:p>42</j.0:p>
</rdf:Description>
</rdf:RDF>
So here’s the mysterious j.0
appearing. What’s going on? The j.0
is an XML
namespace. It’s defined in the root element of the RDF file:
xmlns:j.0="http://example.com/foo#"
To get the full URI, just replace j.0:
with the URI defined in the namespace
declaration. But why was it put there at all? Consider the alternative. With
RDF’s striping XML syntax, elements are alternately resource and property
names. Suppose we hadn’t used a namespace for p
:
<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" >
<rdf:Description rdf:about="http://example.com/foo#r">
<http://example.com/foo#p>42</http://example.com/foo#p>
</rdf:Description>
</rdf:RDF>
<http://example.com/foo#p>
isn’t a legal XML element name. It contains
characters (such as colon) that are not syntactically permitted in an XML
element name. So, using XML’s namespace mechanism gets us out of a hole when we
want RDF identifiers in XML to be URI’s. It also has value in its own right
though: semantically your p
relation may denote something different to my p
relation; if we put them in different namespaces there’s much less chance of an
accidental confusion of semantics.
So, now that we know why j.0
appears, what can we do? One solution is to
not use XML output. The same example, written in N3 format instead of RDF/XML,
becomes:
<http://example.com/foo#r>
<http://example.com/foo#p>
"42" .
No funny prefixes in sight. Alternatively, we can just ensure that we use a
sensible name for the namespace instead of Jena’s autogenerated j.0
, j.1
,
etc. The key to this is the
PrefixMapping
interface, which is a super-interface of Model
. The method setNsPrefix
lets
us assign a more meaningful (to human readers!) namespace:
public static void main( String\[\] args ) {
Model m = ModelFactory.createDefaultModel();
String NS = "http://example.com/foo#";
m.setNsPrefix( "eg", NS );
Property p = m.createProperty( NS + "p" );
Resource r = m.createResource( NS + "r" );
r.addProperty( p, 42 );
m.write( System.out, "RDF/XML" );
}
Producing:
<rdf:RDF
xmlns:eg="http://example.com/foo#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" >
<rdf:Description rdf:about="http://example.com/foo#r">
<eg:p>42</eg:p>
</rdf:Description>
</rdf:RDF>