RDF Resources and Literals
This section will describe RDF resources and literals.
RDF resources can be retrieved using the RDF service. They are identified by a URI. You cannot use a string directly, you must get a resource object using the RDF service. Datasources store references to these resources. As with datasources, the RDF service has a facility for caching resource objects. When a request is made for a resource that is already in the cache, the cached version will be returned. That means that every reference to a resource will be the same. In native code, each reference will have the same pointer so they can be compared without having to do a potentially more costly string comparison.
Since the resource is cached, it is globally unique. If several datasources refer to the same resource, they will both refer to the same thing. This makes it easy to combine several datasources together in a single composite-datasource and have the data from all the datasources appear as if it was blended together.
A resource can be retrieved from the RDF service using the GetResource method. This method should be passed the URI of the resource and it will return a resource object corresponding to that URI. For example:
var res = rdfService.GetResource("http://www.xulplanet.com/rdf/people/Karen");
Anonymous nodes are those that do not have a URI, and are often used as placeholders in the RDF graph. Mozilla handles blank nodes or anonymous nodes by assigning them a randomly generated URI. That means that anonymous resources are handled the same way as other resources except that the URIs are generated. Although you shouldn't use the resource URIs directly, they always begin with the string 'rdf:#$' followed by a few random letters and numbers. The method GetAnonymousResource of the RDF service can be used to retrieve anonymous resources. It does not take a URI as an argument, since it will be generated.
var res = rdfService.GetAnonymousResource();
When the GetResource method is called, the RDF service will look in the cache to see if the resource is already cached. If it is, the cached resource will be returned. If the resource is not cached, the RDF service will create a new resource object and return it. Similar to how the way the RDF service handles datasources, the resources are not cached directly by the RDF service. This is handled in the resource's Init method, which will be called just before the GetResource method returns.
The resource will call the RDF service's RegisterResource method to cache the resource. When the last reference to the resource is dropped, the resource object will be deleted and the resource will call the UnregisterResource method of the RDF service to remove the resource from the cache.
When the service creates a new resource, it finds a factory object that is capable of creating the resource. The factory is responsible for allocating the resource. In almost all cases, the default factory will be used which creates standard resource objects. It is possible to have a different factory create the resources if there was a need for special proccessing. The factory will be looked up using the scheme of the resource URI. For instance, if the resource's URI was 'http://www.example.com/resource/', the URI scheme would be 'http', so a factory that generated 'http' resources would be used. Note that this has nothing to do with HTTP web sites. If the URI was 'urn:sample', a 'urn' factory would be used.
This mechanism allows a custom native component to have a different resource implementation. The RDF service will look for a component of the form @mozilla.org/rdf/resource-factory;1?name=<scheme> where <scheme> is the URL scheme. This component will be used to create the resource objects. This feature is used by Mozilla's mail application to create specialized resources. However, this feature isn't particularly necessary for general purposes and should be avoided. In most cases, a factory will not be found and a default resource will be created.
Once you have a resource object, you can get its URI by retrieving the Value property. You can't change the URI with this property -- you must get a resource object using the RDF service's GetResource method. Here is an example which retrieves a resource and displays its URI:
var res = rdfService.GetResource("http://www.xulplanet.com/rdf/people/Sandra"); alert(res.Value);
Mozilla handles RDF literals in a similar fashion. They should be retrieved using the RDF service and are cached so that the same object is returned each time a literal is asked for. Literals are identified by their string contents. You cannot create custom types of literals and retrieve them through the RDF service.
Mozilla supports a number of different types of literals, mostly for convenience. The types are summarized below:
|Type||XPCOM Interface||RDF Service method||Description|
|String||nsIRDFLiteral||GetLiteral||String of any length|
|Date||nsIRDFDate||GetDateLiteral||A date/time, initialized using a 64-bit number of microseconds since January 1, 1970 GMT|
|Blob||nsIRDFBlob||GetBlobLiteral||Any binary data. This type is not scriptable.|
Also listed in the table is the method of the RDF service that one would call to retrieve a literal of the desired type. All of the literal types are cached, which means that each request to get the integer literal '7' will return the same object.
For example, to retrieve a string literal, one can use:
var house = rdfService.GetLiteral("House");
In RDF/XML files, you can use an extra attribute to indicate which type of literal to use. In the newer RDF proposed specifications, one would use the rdf:datatype attribute to indicate a literal's type. Mozilla's RDF parser doesn't implement this yet since it was written long before the newer features were specified, but a similar feature is available. Instead, the type is indicated by adding a NC:parseType attribute to a literal. The 'NC' namespace is 'http://home.netscape.com/NC-rdf#'. The following is an example:
<?xml version="1.0"?> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:NC="http://home.netscape.com/NC-rdf#"> xmlns:sample="http://www.xulplanet.com/rdf/example/"> <rdf:Description rdf:about="urn:person:Sandra"> <sample:age NC:parseType="Integer">16</sample:age> </rdf:Description> </rdf:RDF>
As with resources, literals also have a Value property which can be used to get the literal's value.
All RDF resources implement the nsIRDFResource interface and all literals implement one of the interfaces listed in the table above. All of the resource and literal interfaces are subinterfaces of the more general interface nsIRDFNode. This interface represents a node in the RDF graph and is available for all resources and literals. Datasource query methods that can return either a resource or a literal will return a node and you can use QueryInterface to cast a node to the more specific type. Query methods that can only return a resource would return the nsIRDFResource directly.
The nsIRDFNode interface has a single method, EqualsNode which may be used to compare two nodes without having to cast them. This method will return true if the two nodes are the same type and have the same value.
RDF delegates are a way in which to attach an object to an RDF resource which will automatically be kept until the resource is no longer being used. When the resource is deleted, the delegate is released and may be deleted afterwards, assuming it isn't being used by something else. You probably wouldn't use delegates for your own purposes, so they are described only briefly below.
numbered list of sources
- list of predicates
> list of targets
var rdfService = Components.classes["@mozilla.org/rdf/rdf-service;1"].
var ds = rdfService.GetDataSource(datasource_name);
for(var r=0; all_res.hasMoreElements(); r++)
if(t.length>5000) break; // comment out for unlimited output
// res is a resource
if (res instanceof Components.interfaces.nsIRDFResource)
var tr=r + " R: "+res.Value+"\n";
var ps= ds.ArcLabelsOut(res);
var predicate = ps.getNext();
// predicate is a resource
if (predicate instanceof Components.interfaces.nsIRDFResource)
tr+=" -R: "+predicate.Value+"\n";
var ts= ds.GetTargets(res, predicate, true);
var target = ts.getNext();
// target is either a resource, a literal or a typed-literal
if (target instanceof Components.interfaces.nsIRDFResource)
tr+=" >R: "+target.Value+"\n";
if (target instanceof Components.interfaces.nsIRDFLiteral)
tr+=" >L: "+target.Value+"\n";
if (target instanceof Components.interfaces.nsIRDFBlob)
tr+=" >BLOB length:"+target.length+"\n";
if (target instanceof Components.interfaces.nsIRDFInt)
if (target instanceof Components.interfaces.nsIRDFDate)
tr+=" >DATE: "+target.Value+"\n";
if (target instanceof Components.interfaces.nsIRDFNode)
tr+=" >Node \n";
} // end predicate-res
} // end ps
} else // should never happen
if (res instanceof Components.interfaces.nsIRDFLiteral)
t+=r + "L: "+res.Value+"\n";
t+=r + "?: "+"\n";
note: in firefox typed-literal's (my name for it) are defined by "NC:parseType" which is different than the latest RDF specification.