宜人贷只有公积金模式:An Introduction to RDF and the Jena RDF API

来源:百度文库 编辑:中财网 时间:2024/04/27 19:38:04

An Introduction to RDF and the Jena RDF API


Preface

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 isunfamiliar with RDF and who learns best by prototyping, or, for otherreasons, wishes to move quickly to implementation. Some familiaritywith both XML and Java is assumed.

Implementing too quickly, without first understanding the RDF data model,leads to frustration and disappointment. Yet studying the data modelalone is dry stuff and often leads to tortuous metaphysical conundrums. Itis better to approach understanding both the data model and how to use it inparallel. Learn a bit of the data model and try it out. Thenlearn a bit more and try that out. Then the theory informs the practiceand the practice the theory. The data model is quite simple, so thisapproach does not take long.

RDF has an XML syntax and many who are familiar with XML will think of RDFin terms of that syntax. This is mistake. RDF should beunderstood in terms of its data model. RDF data can be represented inXML, but understanding the syntax is secondary to understanding the datamodel.

An implementation of the Jena API, including the working source code forall the examples used in this tutorial can be downloaded from http://jena.sourceforge.net/downloads.html.


Table of Contents

  1. Introduction
  2. Statements
  3. Writing RDF
  4. Reading RDF
  5. Controlling Prefixes
  6. Jena RDF Packages
  7. Navigating a Model
  8. Querying a Model
  9. Operations on Models
  10. Containers
  11. More about Literals and Datatypes
  12. Glossary

Introduction

The Resource Description Framework (RDF) is a standard (technically a W3CRecommendation) for describing resources. What is a resource? That israther a deep question and the precise definition is still the subject ofdebate. For our purposes we can think of it as anything we can identify.You are a resource, as is your home page, this tutorial, the number one andthe great white whale in Moby Dick.

Our examples in this tutorial will be about people. They use an RDF representation of VCARDS. RDFis best thought of in the form of node and arc diagrams. A simple vcardmight look like this in RDF:

The resource, John Smith, is shown asan elipse and is identified by a Uniform Resource Identifier (URI)1, in this case"http://.../JohnSmith". If you try to access that resource using yourbrowser, you are unlikely to be successful; April the first jokes notwithstanding, you would be rather surprised if your browser were able todeliver John Smith to your desk top. If you are unfamiliar with URI's,think of them simply as rather strange looking names.

Resources have properties. In theseexamples we are interested in the sort of properties that would appear onJohn Smith's business card. Figure 1 shows only one property, JohnSmith's full name. A property is represented by an arc, labeled with thename of a property. The name of a property is also a URI, but as URI's arerather long and cumbersome, the diagram shows it in XML qname form. Thepart before the ':' is called a namespace prefix and represents anamespace. The part after the ':' is called a local name and representsa name in that namespace. Properties are usually represented in thisqname form when written as RDF XML and it is a convenient shorthand forrepresenting them in diagrams and in text. Strictly, however,properties are identified by a URI. The nsprefix:localname form is ashorthand for the URI of the namespace concatenated with the localname.There is no requirement that the URI of a property resolve to anything whenaccessed by a browser.

Each property has a value. In this case the value is a literal, which for now we can think of as astrings of characters2.Literals are shown in rectangles.

Jena is a Java API which can be used to create and manipulate RDF graphslike this one. Jena has object classes to represent graphs, resources,properties and literals. The interfaces representing resources,properties and literals are called Resource, Property and Literalrespectively. In Jena, a graph is called a model and is represented by the Modelinterface.

The code to create this graph, or model, is simple:

// some definitionsstatic String personURI    = "http://somewhere/JohnSmith";static String fullName     = "John Smith";// create an empty ModelModel model = ModelFactory.createDefaultModel();// create the resourceResource johnSmith = model.createResource(personURI);// add the property johnSmith.addProperty(VCARD.FN, fullName);

It begins with some constant definitions and then creates an empty Modelor model, using the ModelFactory method createDefaultModel()to create a memory-based model. Jena contains other implementationsof the Model interface, e.g one which uses a relational database: thesetypes of Model are also available from ModelFactory.

The John Smith resource is then created and a property added to it.The property is provided by a "constant" class VCARD which holds objectsrepresenting all the definitions in the VCARD schema. Jena provides constantclasses for other well known schemas, such as RDF and RDF schema themselves,Dublin Core and DAML.

The code to create the resource and add the property, can be morecompactly written in a cascading style:

Resource johnSmith =        model.createResource(personURI)             .addProperty(VCARD.FN, fullName);

The working code for this example can be found in the /src-examples directory ofthe Jena distribution as tutorial 1. Asan exercise, take this code and modify it to create a simple VCARD foryourself.

Now let's add some more detail to the vcard, exploring some more featuresof RDF and Jena.

In the first example, the property value was a literal. RDFproperties can also take other resources as their value. Using a common RDFtechnique, this example shows how to represent the different parts of JohnSmith's name:

Here we have added a new property, vcard:N, to represent the structure ofJohn Smith's name. There are several things of interest about thisModel. Note that the vcard:N property takes a resource as its value.Note also that the ellipse representing the compound name has no URI.It is known as an blank Node.

The Jena code to construct this example, is again very simple. Firstsome declarations and the creation of the empty model.

// some definitionsString personURI    = "http://somewhere/JohnSmith";String givenName    = "John";String familyName   = "Smith";String fullName     = givenName + " " + familyName;// create an empty ModelModel model = ModelFactory.createDefaultModel();// create the resource//   and add the properties cascading styleResource johnSmith  = model.createResource(personURI)         .addProperty(VCARD.FN, fullName)         .addProperty(VCARD.N,                      model.createResource()                           .addProperty(VCARD.Given, givenName)                           .addProperty(VCARD.Family, familyName));

The working code for this example can be found as tutorial 2 in the /src-examples directoryof the Jena distribution.


Statements

Each arc in an RDF Model is called a statement. Each statement asserts a factabout a resource. A statement has three parts:

  • the subject is the resource from which the arc leaves
  • the predicate is the property that labels the arc
  • the object is the resource or literal pointed to by the arc

A statement is sometimes called a triple,because of its three parts.

An RDF Model is represented as a set of statements. Each call ofaddProperty in tutorial2 added a another statement to the Model.(Because a Model is set of statements, adding a duplicate of a statement has noeffect.) The Jena model interface defines a listStatements()method which returns an StmtIterator, a subtype of Java'sIterator over all all the statements in a Model.StmtIterator has a method nextStatement()which returns the next statement from the iterator (the same one thatnext() would deliver, already cast to Statement).The Statement interface provides accessormethods to the subject, predicate and object of a statement.

Now we will use that interface to extend tutorial2 to list all thestatements created and print them out. The complete code for this can befound in tutorial 3.

// list the statements in the ModelStmtIterator iter = model.listStatements();// print out the predicate, subject and object of each statementwhile (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(" .");} 

Since the object of a statement can be either a resource or a literal, thegetObject() method returns anobject typed as RDFNode, which is acommon superclass of both Resourceand Literal. The underlying objectis of the appropriate type, so the code uses instanceof todetermine which andprocesses it accordingly.

When run, this program should produce output resembling:

http://somewhere/JohnSmith http://www.w3.org/2001/vcard-rdf/3.0#N anon:14df86:ecc3dee17b:-7fff .anon:14df86:ecc3dee17b:-7fff http://www.w3.org/2001/vcard-rdf/3.0#Family  "Smith" .anon:14df86:ecc3dee17b:-7fff 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 you know why it is clearer to draw Models. If you look carefully, youwill see that each line consists of three fields representing the subject,predicate and object of each statement. There are four arcs in the Model, sothere are four statements. The "anon:14df86:ecc3dee17b:-7fff" is an internalidentifier generated by Jena. It is not a URI and should not be confusedwith one. It is simply an internal label used by the Jena implementation.

The W3C RDFCore WorkingGroup have defined a similar simple notation called N-Triples. The namemeans "triple notation". We will see in the next section that Jena has anN-Triples writer built in.


Writing RDF

Jena has methods for reading and writing RDF as XML. These can beused to save an RDF model to a file and later read it back in again.

Tutorial 3 created a model and wrote it out in triple form. Tutorial 4 modifies tutorial 3 to write themodel in RDF XML form to the standard output stream. The code again, isvery simple: model.write can take an OutputStreamargument.

// now write the model in XML form to a filemodel.write(System.out);

The output should look something like this:

      John Smith            John    Smith  

The RDF specifications specify how to represent RDF as XML. The RDFXML syntax is quite complex. The reader is referred to the primer being developed by theRDFCore WG for a more detailed introduction. However, let's take a quick lookat how to interpret the above.

RDF is usually embedded in an element. The element isoptional if there are other ways of know that some XML is RDF, but it isusually present. The RDF element defines the two namespaces used in thedocument. There is then an element which describesthe resource whose URI is "http://somewhere/JohnSmith". If the rdf:aboutattribute was missing, this element would represent a blank node.

The element describes a property of the resource. Theproperty name is the "FN" in the vcard namespace. RDF converts this to a URIreference by concatenating the URI reference for the namespace prefix and"FN", the local name part of the name. This gives a URI reference of"http://www.w3.org/2001/vcard-rdf/3.0#FN". The value of the propertyis the literal "John Smith".

The element is a resource. In this case the resource isrepresented by a relative URI reference. RDF converts this to an absoluteURI reference by concatenating it with the base URI of the currentdocument.

There is an error in this RDF XML; it does not exactly represent the Modelwe created. The blank node in the Model has been given a URI reference. Itis no longer blank. The RDF/XML syntax is not capable of representing allRDF Models; for example it cannot represent a blank node which is the objectof two statements. The 'dumb' writer we used to write this RDF/XML makes noattempt to write correctly the subset of Models which can be writtencorrectly. It gives a URI to each blank node, making it no longer blank.

Jena has an extensible interface which allows new writers for differentserialization languages for RDF to be easily plugged in. The above callinvoked the standard 'dumb' writer. Jena also includes a more sophisticatedRDF/XML writer which can be invoked by specifying another argument to thewrite() method call:

// now write the model in XML form to a filemodel.write(System.out, "RDF/XML-ABBREV"); 

This writer, the so called PrettyWriter, takes advantage of features ofthe RDF/XML abbreviated syntax to write a Model more compactly. It is alsoable to preserve blank nodes where that is possible. It is however, notsuitable for writing very large Models, as its performance is unlikely to beacceptable. To write large files and preserve blank nodes, write inN-Triples format:

// now write the model in XML form to a filemodel.write(System.out, "N-TRIPLE");  

This will produce output similar to that of tutorial 3 which conforms tothe N-Triples specification.


Reading RDF

Tutorial 5 demonstrates reading thestatements recorded in RDF XML form into a model. With this tutorial,we have provided a small database of vcards in RDF/XML form. The followingcode will read it in and write it out. Note that for this application torun, the input file must be in the current directory.

 // create an empty model Model model = ModelFactory.createDefaultModel(); // use the FileManager to find the input file InputStream in = FileManager.get().open( inputFileName );if (in == null) {    throw new IllegalArgumentException(                                 "File: " + inputFileName + " not found");}// read the RDF/XML filemodel.read(in, null);// write it to standard outmodel.write(System.out);      

The second argument to the read() method call is the URI which willbe used for resolving relative URI's. As there are no relative URIreferences in the test file, it is allowed to be empty. When run, tutorial 5 will produce XML output whichlooks like:

      Smith    John        John Smith            Sarah Jones            Matt Jones            Smith    Rebecca        Jones    Sarah        Jones    Matthew        Becky Smith      

Controlling Prefixes

explicit prefix definitions

In the previous section, we saw that the output XML declared a namespaceprefix vcard and used that prefix to abbreviate URIs. While RDFuses only the full URIs, and not this shortened form, Jena provides waysof 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 three lots of RDF/XML, withthree different prefix mappings. First the default, with noprefixes other than the standard ones:
# -- no special prefixes defined                    
We see that the rdf namespace is declared automatically, since itis required for tags such as and. Namespace declarations are alsoneeded for using the two properties P and Q, but since theirnamespaces have not been introduced to the model, they get inventednamespace names: j.0 and j.1.

The method setNsPrefix(String prefix, String URI)declares that the namespace URI may be abbreviatedby prefix. Jena requires that prefix bea legal XML namespace name, and that URI ends with anon-name character. The RDF/XML writer will turn these prefixdeclarations into XML namespace declarations and use them in itsoutput:

# -- nsA defined                    
The other namespace still gets the constructed name, but the nsA nameis now used in the property tags. There's no need for the prefix nameto have anything to do with the variables in the Jena code:
# -- nsA and cat defined                    
Both prefixes are used for output, and no generated prefixes are needed.

implicit prefix definitions

As well as prefix declarations provided by calls to setNsPrefix,Jena will remember the prefixes that were used in input tomodel.read().

Take the output produced by the previous fragment, and paste it intosome file, with URL file:/tmp/fragment.rdf say. Then run thecode:

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 canremove a prefix with removeNsPrefix(String prefix) if youdon't want it in the output.

Since NTriples doesn't have any short way of writing URIs, it takesno notice of prefixes on output and doesn't provide any on input. Thenotation N3, also supported by Jena, does have short prefixed names,and records them on input and uses them on output.

Jena has further operations on the prefix mappings that a model holds,such as extracting a Java Map of the exiting mappings, oradding a whole group of mappings at once; see the documentation forPrefixMapping for details.


Jena RDF Packages

Jena is a Java API for semantic web applications. The key RDF package forthe application developer iscom.hp.hpl.jena.rdf.model. The API has been definedin terms of interfaces so that application code can work with differentimplementations without change. This package contains interfaces forrepresenting models, resources, properties, literals, statements and all theother key concepts of RDF, and a ModelFactory for creating models. So thatapplication code remains independent ofthe implementation, it is best if it uses interfaces wherever possible, notspecific class implementations.

The com.hp.hpl.jena.tutorial package contains theworking source code for all the examples used in this tutorial.

The com.hp.hpl.jena...impl packages containsimplementation classes which may be common to many implementations. Forexample, they defines classes ResourceImpl,PropertyImpl, and LiteralImpl which may beused directly or subclassed by different implementations. Applicationsshould rarely, if ever, use these classes directly. For example, ratherthan creating a new instance of ResourceImpl, it is better touse the createResource method of whatever model is beingused. That way, if the model implementation has used an optimizedimplementation of Resource, then no conversions between the twotypes will be necessary.


Navigating a Model

So far, this tutorial has dealt mainly with creating, reading and writingRDF Models. It is now time to deal with accessing information held in aModel.

Given the URI of a resource, the resource object can be retrieved from amodel using the Model.getResource(String uri) method. Thismethod is defined to return a Resource object if one exists in the model, orotherwise to create a new one. For example, to retrieve the Adam Smithresource from the model read in from the file in tutorial 5:

// retrieve the John Smith vcard resource from the modelResource vcard = model.getResource(johnSmithURI);  

The Resource interface defines a number of methods for accessing theproperties of a resource. The Resource.getProperty(Propertyp) method accesses a property of the resource. This method doesnot follow the usual Java accessor convention in that the type of the objectreturned is Statement, not the Property that youmight have expected. Returning the whole statement allows the application toaccess the value of the property using one of its accessor methods whichreturn the object of the statement. For example to retrieve theresource which is the value of the vcard:N property:

// retrieve the value of the N propertyResource name = (Resource) vcard.getProperty(VCARD.N)                                .getObject();

In general, the object of a statement could be a resource or a literal, sothe application code, knowing the value must be a resource, casts thereturned object. One of the things that Jena tries to do is to providetype specific methods so the application does not have to cast and typechecking can be done at compile time. The code fragment above, can bemore conveniently written:

// retrieve the value of the FN propertyResource name = vcard.getProperty(VCARD.N)                     .getResource();

Similarly, the literal value of a property can be retrieved:

// retrieve the given name propertyString fullName = vcard.getProperty(VCARD.FN)                        .getString();

In this example, the vcard resource has only one vcard:FN andone vcard:N property. RDF permits a resource to repeat aproperty; for example Adam might have more than one nickname. Let's give himtwo:

// add two nickname properties to vcardvcard.addProperty(VCARD.NICKNAME, "Smithy")     .addProperty(VCARD.NICKNAME, "Adman");

As noted before, Jena represents an RDF Model as set ofstatements, so adding a statement with the subject, predicate and object asone already in the Model will have no effect. Jena does not define which ofthe two nicknames present in the Model will be returned. The result ofcalling vcard.getProperty(VCARD.NICKNAME) is indeterminate. Jenawill return one of the values, but there is no guarantee even that twoconsecutive calls will return the same value.

If it is possible that a property may occur more than once, then theResource.listProperties(Property p) method can be used to return an iteratorwhich will list them all. This method returns an iterator which returnsobjects of type Statement. We can list the nicknames likethis:

// set up the outputSystem.out.println("The nicknames of \""                      + fullName + "\" are:");// list the nicknamesStmtIterator iter = vcard.listProperties(VCARD.NICKNAME);while (iter.hasNext()) {    System.out.println("    " + iter.nextStatement()                                    .getObject()                                    .toString());}

This code can be found in tutorial 6.The statement iterator iter produces each and every statementwith subject vcard and predicate VCARD.NICKNAME,so looping over it allows us to fetch each statement by usingnextStatement(), get the object field, and convert it toa string.The code produces the following output when run:

The nicknames of "John Smith" are:    Smithy    Adman

All the properties of a resource can be listed by using thelistProperties() method without an argument.


Querying a Model

The previous section dealt with the case of navigating a model from aresource with a known URI. This section deals with searching amodel. The core Jena API supports only a limited query primitive. Themore powerful query facilities of RDQL are described elsewhere.

The Model.listStatements() method, which lists all thestatements in a model, is perhaps the crudest way of querying a model.Its use is not recommended on very large Models.Model.listSubjects() is similar, but returns an iterator overall resources that have properties, ie are the subject of somestatement.

Model.listSubjectsWithProperty(Property p, RDFNodeo) will return an iterator over all the resources whichhave property p with value o. If we assume thatonly vcard resourceswill have vcard:FN property, and that in our data, all suchresources have such a property, then we can find all the vcards like this:

// list vcardsResIterator iter = model.listSubjectsWithProperty(VCARD.FN);while (iter.hasNext()) {    Resource r = iter.nextResource();    ...}

All these query methods are simply syntactic sugar over a primitive querymethod model.listStatements(Selector s). This method returns aniterator over all the statements in the model 'selected' by s.The selector interface is designed to be extensible, but for now, there isonly one implementation of it, the class SimpleSelector from thepackage com.hp.hpl.jena.rdf.model. UsingSimpleSelector is one of the rare occasions in Jena when it isnecessary to use a specific class rather than an interface. TheSimpleSelector constructor takes three arguments:

Selector selector = new SimpleSelector(subject, predicate, object)  

This selector will select all statements with a subject that matchessubject, a predicate that matches predicate and anobject that matches object. If a null is suppliedin any of the positions, it matches anything; otherwise they match correspondingequal resources or literals. (Two resources are equal if they have equal URIsor are the same blank node; two literals are the same if all their componentsare equal.) Thus:

Selector selector = new SimpleSelector(null, null, null);  

will select all the statements in a Model.

Selector selector = new SimpleSelector(null, VCARD.FN, null);  

will select all the statements with VCARD.FN as their predicate, whateverthe subject or object. As a special shorthand,

listStatements( S, P, O )
is equivalent to
listStatements( new SimpleSelector( S, P, O ) )

The following code, which can be found in full in tutorial 7 lists the full names on all thevcards in the database.

// select all the resources with a VCARD.FN propertyResIterator iter = model.listSubjectsWithProperty(VCARD.FN);if (iter.hasNext()) {    System.out.println("The database contains vcards for:");    while (iter.hasNext()) {        System.out.println("  " + iter.nextStatement()                                      .getProperty(VCARD.FN)                                      .getString());    }} else {    System.out.println("No vcards were found in the database");}            

This should produce output similar to the following:

The database contains vcards for:  Sarah Jones  John Smith  Matt Jones  Becky Smith  

Your next exercise is to modify this code to use SimpleSelectorinstead of listSubjectsWithProperty.

Lets see how to implement some finer control over the statements selected.SimpleSelector can be subclassed and its selects method modifiedto perform further filtering:

// 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");}    });

This sample code uses a neat Java technique of overridding a methoddefinition inline when creating an instance of the class. Here theselects(...) method checks to ensure that the full name endswith "Smith". It is important to note that filtering based on the subject,predicate and object arguments takes place before theselects(...) method is called, so the extra test will only beapplied to matching statements.

The full code can be found in tutorial8 and produces output like this:

The database contains vcards for:  John Smith  Becky Smith

You might think that:

// do all filtering in the selects methodStmtIterator 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))          }     } });

is equivalent to:

StmtIterator iter =  model.listStatements(new SimpleSelector(subject, predicate, object)

Whilst functionally they may be equivalent, the first form will list allthe statements in the Model and test each one individually, whilst the secondallows indexes maintained by the implementation to improve performance. Tryit on a large Model and see for yourself, but make a cup of coffee first.


Operations on Models

Jena provides three operations for manipulating Models as a whole. Theseare the common set operations of union, intersection and difference.

The union of two Models is the union of the sets of statements whichrepresent each Model. This is one of the key operations that the design ofRDF supports. It enables data from disparate data sources to be merged.Consider the following two Models:

and

When these are merged, the two http://...JohnSmith nodes are merged intoone and the duplicate vcard:FN arc is dropped to produce:

Lets look at the code to do this (the full code is in tutorial 9) and see what happens.

// read the RDF/XML filesmodel1.read(new InputStreamReader(in1), "");model2.read(new InputStreamReader(in2), "");// merge the ModelsModel model = model1.union(model2);// print the Model as RDF/XMLmodel.write(system.out, "RDF/XML-ABBREV");

The output produced by the pretty writer looks like this:

                    John@somewhere.com                    John      Smith        John Smith  
 

Even if you are unfamiliar with the details of the RDF/XML syntax, itshould be reasonably clear that the Models have merged as expected. Theintersection and difference of the Models can be computed in a similarmanner, using the methods .intersection(Model) and.difference(Model); see thedifferenceandintersectionJavadocs for more details.


Containers

RDF defines a special kind of resources for representing collections ofthings. These resources are called containers. The members of acontainer can be either literals or resources. There are three kinds ofcontainer:

  • a BAG is an unordered collection
  • an ALT is an unordered collection intended to represent alternatives
  • a SEQ is an ordered collection

A container is represented by a resource. That resource will have anrdf:type property whose value should be one of rdf:Bag, rdf:Alt or rdf:Seq,or a subclass of one of these, depending on the type of the container.The first member of the container is the value of the container's rdf:_1property; the second member of the container is the value of the container'srdf:_2 property and so on. The rdf:_nnn properties are known as theordinal properties.

For example, the Model for a simple bag containing the vcards of theSmith's might look like this:

Whilst the members of the bag are represented by theproperties rdf:_1, rdf:_2 etc the ordering of the properties is notsignificant. We could switch the values of the rdf:_1 and rdf:_2properties and the resulting Model would represent the same information.

Alt's are intended to represent alternatives. Forexample, lets say a resource represented a software product. It mighthave a property to indicate where it might be obtained from. The valueof that property might be an Alt collection containing various sites fromwhich it could be downloaded. Alt's are unordered except that therdf:_1 property has special significance. It represents the defaultchoice.

Whilst containers can be handled using the basic machinery ofresources and properties, Jena has explicit interfaces and implementationclasses to handle them. It is not a good idea to have an objectmanipulating a container, and at the same time to modify the state of thatcontainer using the lower level methods.

Let's modify tutorial 8 to create this bag:

// create a bagBag 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 bagwhile (iter.hasNext()) {    smiths.add(iter.nextStatement().getSubject());}

If we write out this Model, it contains something like the following:

...                

which represents the Bag resource.

The container interface provides an iterator to list the contents of acontainer:

// print out the members of the bagNodeIterator 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");}

which produces the following output:

The bag contains:  John Smith  Becky Smith

Executable example code can be found in tutorial 10, which glues together the fragments above into a completeexample.

The Jena classes offer methods for manipulating containers includingadding new members, inserting new members into the middle of a container andremoving existing members. The Jena container classes currently ensure thatthe the list of ordinal properties used starts at rdf:_1 and is contiguous.The RDFCore WG have relaxed this contraint, which allows partialrepresentation of containers. This therefore is an area of Jena may bechanged in the future.


More about Literals andDatatypes

RDF literals are not just simple strings. Literals may have a languagetag to indicate the language of the literal. The literal "chat" with anEnglish language tag is considered different to the literal "chat" with aFrench language tag. This rather strange behaviour is an artefact of theoriginal RDF/XML syntax.

Further there are really two sorts of Literals. In one, the stringcomponent is just that, an ordinary string. In the other the stringcomponent is expected to be a well balanced fragment of XML. When an RDFModel is written as RDF/XML a special construction using aparseType='Literal' attribute is used to represent it.

In Jena, these attributes of a literal may be set when the literal isconstructed, e.g. in tutorial 11:

// create the resourceResource r = model.createResource();// add the propertyr.addProperty(RDFS.label, model.createLiteral("chat", "en")) .addProperty(RDFS.label, model.createLiteral("chat", "fr")) .addProperty(RDFS.label, model.createLiteral("chat", true));// write out the Modelmodel.write(system.out);

produces

      chat    chat    chat  

For two literals to be considered equal, they must either both be XMLliterals or both be simple literals. In addition, either both must have nolanguage tag, or if language tags are present they must be equal. For simpleliterals the strings must be equal. XML literals have two notions ofequality. The simple notion is that the conditions previously mentioned aretrue and the strings are also equal. The other notion is that they can beequal if the cannonicalization of their strings is equal.

Jena's interfaces also support typed literals. The old-fashioned way(shown below) treats typed literals as shorthand for strings: typedvalues are converted in the usual Java way to strings and these stringsare stored in the Model. For example, try (noting that forsimple literals, we can omit the model.createLiteral(...)call):

// create the resourceResource r = model.createResource();// add the propertyr.addProperty(RDFS.label, "11") .addProperty(RDFS.label, 11);// write out the Modelmodel.write(system.out, "N-TRIPLE");

The output produced is:

_:A...  "11" .

Since both literals are really just the string "11", then only onestatement is added.

The RDFCore WG has defined mechanisms for supporting datatypes in RDF.Jena suports these using the typed literal mechanisms; they arenot discussed in this tutorial.


Glossary

Blank Node
Represents a resource, but does not indicate a URI for theresource. Blank nodes act like existentially qualified variables in firstorder logic.
Dublin Core
A standard for metadata about web resources. Furtherinformation can be found at the Dublin Coreweb site.
Literal
A string of characters which can be the value of a property.
Object
The part of a triple which is the value of the statement
Predicate
The property part of a triple.
Property
A property is an attribute of a resource. For exampleDC.title is a property, as is RDF.type.
Resource
Some entity. It could be a web resource such as web page, orit could be a concrete physical thing such as a tree or a car. It could be anabstract idea such as chess or football. Resources are named by URI's.
Statement
An arc in an RDF Model, normally interpreted as a fact.
Subject
The resource which is the source of an arc in an RDF Model
Triple
A structure containing a subject, a predicate and an object.Another term for a statement.

Footnotes

  1. The identifier of an RDF resource can include a fragment identifier, e.g. http://hostname/rdf/tutorial/#ch-Introduction, so, strictly speaking, an RDF resource is identified by a URI reference.
  2. As well as being a string of characters, literals also have an optional language encoding to represent the language of the string. For example the literal "two" might have a language encoding of "en" for English and the literal "deux" might have a language encoding of "fr" for France.

Author: Brian McBride
Updated by: Daniel Boothby and Chris Dollin
$Id: index.html,v 1.25 2010/12/17 14:22:26 andy_seaborne Exp $