This is a tutorial introduction to both W3C's Resource Description Framework (RDF) and Jena, a Java API for RDF. It is written for the programmer who is unfamiliar with RDF and who learns best by prototyping, or, for other reasons, wishes to move quickly to implementation. Some familiarity with both XML and Java is assumed.
// some definitions static String personURI = "http://somewhere/JohnSmith"; static String fullName = "John Smith"; // create an empty Model Model model = ModelFactory.createDefaultModel(); // create the resource Resource johnSmith = model.createResource(personURI); // add the property johnSmith.addProperty(VCARD.FN, fullName);
Resource johnSmith = model.createResource(personURI) .addProperty(VCARD.FN, fullName);
// some definitions String personURI = "http://somewhere/JohnSmith"; String givenName = "John"; String familyName = "Smith"; String fullName = givenName + " " + familyName; // create an empty Model Model model = ModelFactory.createDefaultModel(); // create the resource // and add the properties cascading style Resource johnSmith = model.createResource(personURI) .addProperty(VCARD.FN, fullName) .addProperty(VCARD.N, model.createResource() .addProperty(VCARD.Given, givenName) .addProperty(VCARD.Family, familyName));
// list the statements in the Model StmtIterator iter = model.listStatements(); // print out the predicate, subject and object of each statement while (iter.hasNext()) { Statement stmt = iter.nextStatement(); // get next statement Resource subject = stmt.getSubject(); // get the subject Property predicate = stmt.getPredicate(); // get the predicate RDFNode object = stmt.getObject(); // get the object System.out.print(subject.toString()); System.out.print(" " + predicate.toString() + " "); if (object instanceof Resource) { System.out.print(object.toString()); } else { // object is a literal System.out.print(" \"" + object.toString() + "\""); } System.out.println(" ."); }
http://somewhere/JohnSmith http://www.w3.org/2001/vcard-rdf/3.0#N 413f6415-c3b0-4259-b74d-4bd6e757eb60 . 413f6415-c3b0-4259-b74d-4bd6e757eb60 http://www.w3.org/2001/vcard-rdf/3.0#Family "Smith" . 413f6415-c3b0-4259-b74d-4bd6e757eb60 http://www.w3.org/2001/vcard-rdf/3.0#Given "John" . http://somewhere/JohnSmith http://www.w3.org/2001/vcard-rdf/3.0#FN "John Smith" .
// now write the model in XML form to a file model.write(System.out);
<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#' xmlns:vcard='http://www.w3.org/2001/vcard-rdf/3.0#' > <rdf:Description rdf:about='http://somewhere/JohnSmith'> <vcard:FN>John Smith</vcard:FN> <vcard:N rdf:nodeID="A0"/> </rdf:Description> <rdf:Description rdf:nodeID="A0"> <vcard:Given>John</vcard:Given> <vcard:Family>Smith</vcard:Family> </rdf:Description> </rdf:RDF>
// now write the model in a pretty form RDFDataMgr.write(System.out, model, Lang.RDFXML);
// now write the model in N-TRIPLES form RDFDataMgr.write(System.out, model, Lang.NTRIPLES);
// create an empty model Model model = ModelFactory.createDefaultModel(); // use the RDFDataMgr to find the input file InputStream in = RDFDataMgr.open( inputFileName ); if (in == null) { throw new IllegalArgumentException("File: " + inputFileName + " not found"); } // read the RDF/XML file model.read(in, null); // write it to standard out model.write(System.out);
<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#' xmlns:vcard='http://www.w3.org/2001/vcard-rdf/3.0#' > <rdf:Description rdf:nodeID="A0"> <vcard:Family>Smith</vcard:Family> <vcard:Given>John</vcard:Given> </rdf:Description> <rdf:Description rdf:about='http://somewhere/JohnSmith/'> <vcard:FN>John Smith</vcard:FN> <vcard:N rdf:nodeID="A0"/> </rdf:Description> <rdf:Description rdf:about='http://somewhere/SarahJones/'> <vcard:FN>Sarah Jones</vcard:FN> <vcard:N rdf:nodeID="A1"/> </rdf:Description> <rdf:Description rdf:about='http://somewhere/MattJones/'> <vcard:FN>Matt Jones</vcard:FN> <vcard:N rdf:nodeID="A2"/> </rdf:Description> <rdf:Description rdf:nodeID="A3"> <vcard:Family>Smith</vcard:Family> <vcard:Given>Rebecca</vcard:Given> </rdf:Description> <rdf:Description rdf:nodeID="A1"> <vcard:Family>Jones</vcard:Family> <vcard:Given>Sarah</vcard:Given> </rdf:Description> <rdf:Description rdf:nodeID="A2"> <vcard:Family>Jones</vcard:Family> <vcard:Given>Matthew</vcard:Given> </rdf:Description> <rdf:Description rdf:about='http://somewhere/RebeccaSmith/'> <vcard:FN>Becky Smith</vcard:FN> <vcard:N rdf:nodeID="A3"/> </rdf:Description> </rdf:RDF>
In the previous section, we saw that the output XML declared a namespace prefix vcard and used that prefix to abbreviate URIs. While RDF uses only the full URIs, and not this shortened form, Jena provides ways of controlling the namespaces used on output with its prefix mappings. Here's a simple example.
Model m = ModelFactory.createDefaultModel(); String nsA = "http://somewhere/else#"; String nsB = "http://nowhere/else#"; Resource root = m.createResource( nsA + "root" ); Property P = m.createProperty( nsA + "P" ); Property Q = m.createProperty( nsB + "Q" ); Resource x = m.createResource( nsA + "x" ); Resource y = m.createResource( nsA + "y" ); Resource z = m.createResource( nsA + "z" ); m.add( root, P, x ).add( root, P, y ).add( y, Q, z ); System.out.println( "# -- no special prefixes defined" ); m.write( System.out ); System.out.println( "# -- nsA defined" ); m.setNsPrefix( "nsA", nsA ); m.write( System.out ); System.out.println( "# -- nsA and cat defined" ); m.setNsPrefix( "cat", nsB ); m.write( System.out );
The output from this fragment is lots of RDF/XML, with three different prefix mappings. First the default, with no prefixes other than the standard ones:
# -- no special prefixes defined <rdf:RDF xmlns:j.0="http://nowhere/else#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:j.1="http://somewhere/else#" > <rdf:Description rdf:about="http://somewhere/else#root"> <j.1:P rdf:resource="http://somewhere/else#x"/> <j.1:P rdf:resource="http://somewhere/else#y"/> </rdf:Description> <rdf:Description rdf:about="http://somewhere/else#y"> <j.0:Q rdf:resource="http://somewhere/else#z"/> </rdf:Description> </rdf:RDF>
We see that the rdf namespace is declared automatically, since it is required for tags such as <rdf:RDF> and <rdf:resource>. XML namespace declarations are also needed for using the two properties P and Q, but since their prefixes have not been introduced to the model in this example, they get invented namespace names: j.0 and j.1.
# -- nsA defined <rdf:RDF xmlns:j.0="http://nowhere/else#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:nsA="http://somewhere/else#" > <rdf:Description rdf:about="http://somewhere/else#root"> <nsA:P rdf:resource="http://somewhere/else#x"/> <nsA:P rdf:resource="http://somewhere/else#y"/> </rdf:Description> <rdf:Description rdf:about="http://somewhere/else#y"> <j.0:Q rdf:resource="http://somewhere/else#z"/> </rdf:Description> </rdf:RDF>
is now used in the property tags. There's no need for the prefix name to have anything to do with the variables in the Jena code:
# -- nsA and cat defined <rdf:RDF xmlns:cat="http://nowhere/else#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:nsA="http://somewhere/else#" > <rdf:Description rdf:about="http://somewhere/else#root"> <nsA:P rdf:resource="http://somewhere/else#x"/> <nsA:P rdf:resource="http://somewhere/else#y"/> </rdf:Description> <rdf:Description rdf:about="http://somewhere/else#y"> <cat:Q rdf:resource="http://somewhere/else#z"/> </rdf:Description> </rdf:RDF>
Both prefixes are used for output, and no generated prefixes are needed.
As well as prefix declarations provided by calls to setNsPrefix, Jena will remember the prefixes that were used in input to model.read().
Model m2 = ModelFactory.createDefaultModel(); m2.read( "file:/tmp/fragment.rdf" ); m2.write( System.out );
You‘ll see that the prefixes from the input are preserved in the output. All the prefixes are written, even if they’re not used anywhere. You can remove a prefix with removeNsPrefix(String prefix) if you don't want it in the output.
// retrieve the John Smith vcard resource from the model Resource vcard = model.getResource(johnSmithURI);
// retrieve the value of the N property Resource name = (Resource) vcard.getProperty(VCARD.N) .getObject();
// retrieve the value of the N property Resource name = vcard.getProperty(VCARD.N) .getResource();
String fullName = vcard.getProperty(VCARD.FN) .getString();
// add two nickname properties to vcard vcard.addProperty(VCARD.NICKNAME, "Smithy") .addProperty(VCARD.NICKNAME, "Adman");
// set up the output System.out.println("The nicknames of \"" + fullName + "\" are:"); // list the nicknames StmtIterator iter = vcard.listProperties(VCARD.NICKNAME); while (iter.hasNext()) { System.out.println(" " + iter.nextStatement() .getObject() .toString()); }
The nicknames of "John Smith" are: Smithy Adman
// list vcards ResIterator iter = model.listSubjectsWithProperty(VCARD.FN); while (iter.hasNext()) { Resource r = iter.nextResource(); ... }
Selector selector = new SimpleSelector(subject, predicate, object);
Selector selector = new SimpleSelector(null, null, null);
Selector selector = new SimpleSelector(null, VCARD.FN, null);
listStatements( S, P, O )
is equivalent to
listStatements( new SimpleSelector( S, P, O ) )
// select all the resources with a VCARD.FN property ResIterator iter = model.listSubjectsWithProperty(VCARD.FN); if (iter.hasNext()) { System.out.println("The database contains vcards for:"); while (iter.hasNext()) { System.out.println(" " + iter.nextResource() .getProperty(VCARD.FN) .getString()); } } else { System.out.println("No vcards were found in the database"); }
The database contains vcards for: Sarah Jones John Smith Matt Jones Becky Smith
// select all the resources with a VCARD.FN property // whose value ends with "Smith" StmtIterator iter = model.listStatements( new SimpleSelector(null, VCARD.FN, (RDFNode) null) { public boolean selects(Statement s) {return s.getString().endsWith("Smith");} });
The database contains vcards for: John Smith Becky Smith
// do all filtering in the selects method StmtIterator iter = model.listStatements( new SimpleSelector(null, null, (RDFNode) null) { public boolean selects(Statement s) { return (subject == null || s.getSubject().equals(subject)) && (predicate == null || s.getPredicate().equals(predicate)) && (object == null || s.getObject().equals(object)) ; } } });
StmtIterator iter = model.listStatements(new SimpleSelector(subject, predicate, object)
// read the RDF/XML files model1.read(new InputStreamReader(in1), ""); model2.read(new InputStreamReader(in2), ""); // merge the Models Model model = model1.union(model2); // print the Model as RDF/XML model.write(system.out, "RDF/XML-ABBREV");
<rdf:RDF xmlns:rdf="<a href="http://www.w3.org/1999/02/22-rdf-syntax-ns#">http://www.w3.org/1999/02/22-rdf-syntax-ns#</a>" xmlns:vcard="http://www.w3.org/2001/vcard-rdf/3.0#"> <rdf:Description rdf:about="http://somewhere/JohnSmith/"> <vcard:EMAIL> <vcard:internet> <rdf:value>John@somewhere.com</rdf:value> </vcard:internet> </vcard:EMAIL> <vcard:N rdf:parseType="Resource"> <vcard:Given>John</vcard:Given> <vcard:Family>Smith</vcard:Family> </vcard:N> <vcard:FN>John Smith</vcard:FN> </rdf:Description> </rdf:RDF>
// create a bag Bag smiths = model.createBag(); // select all the resources with a VCARD.FN property // whose value ends with "Smith" StmtIterator iter = model.listStatements( new SimpleSelector(null, VCARD.FN, (RDFNode) null) { public boolean selects(Statement s) { return s.getString().endsWith("Smith"); } }); // add the Smith's to the bag while (iter.hasNext()) { smiths.add(iter.nextStatement().getSubject()); }
<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#' xmlns:vcard='http://www.w3.org/2001/vcard-rdf/3.0#' > ... <rdf:Description rdf:nodeID="A3"> <rdf:type rdf:resource='http://www.w3.org/1999/02/22-rdf-syntax-ns#Bag'/> <rdf:_1 rdf:resource='http://somewhere/JohnSmith/'/> <rdf:_2 rdf:resource='http://somewhere/RebeccaSmith/'/> </rdf:Description> </rdf:RDF>
// print out the members of the bag NodeIterator iter2 = smiths.iterator(); if (iter2.hasNext()) { System.out.println("The bag contains:"); while (iter2.hasNext()) { System.out.println(" " + ((Resource) iter2.next()) .getProperty(VCARD.FN) .getString()); } } else { System.out.println("The bag is empty"); }
The bag contains: John Smith Becky Smith
// create the resource Resource r = model.createResource(); // add the property r.addProperty(RDFS.label, model.createLiteral("chat", "en")) .addProperty(RDFS.label, model.createLiteral("chat", "fr")) .addProperty(RDFS.label, model.createLiteral("<em>chat</em>", true)); // write out the Model model.write(system.out);
<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#' xmlns:rdfs='http://www.w3.org/2000/01/rdf-schema#' > <rdf:Description rdf:nodeID="A0"> <rdfs:label xml:lang='en'>chat</rdfs:label> <rdfs:label xml:lang='fr'>chat</rdfs:label> <rdfs:label rdf:parseType='Literal'><em>chat</em></rdfs:label> </rdf:Description> </rdf:RDF>
// create the resource Resource r = model.createResource(); // add the property r.addProperty(RDFS.label, "11") .addProperty(RDFS.label, 11); // write out the Model model.write(system.out, "N-TRIPLE");
_:A... <http://www.w3.org/2000/01/rdf-schema#label> "11" .