Chapter 10. RDF, RDF Tools, and the Content Model-P3
10.3.1. What Is an RDF Component?
An RDF component may implement any number of the general RDF
interfaces described here, in addition to special interfaces for accessing and
controlling the data the datasource represents. For example,
@mozilla.org/rdf/datasource;1?name=internetsearch is
an RDF component used to control Mozilla's internet searching facility. In
Mozilla, a component can act as a library of code specific to a given set of
data or domain. The internetsearch component is instantiated and
used to recall text entered in a previous search:
var searchDS =
Components.classes["@mozilla.org/rdf/datasource;1?n
ame=internetsearch"]
.getService(Components.interfaces.nsIInternetSearch
Service);
searchDS.RememberLastSearchText(escapedSearchStr);
This RDF component implements an interface called
nsIInternetSearchService, which is selected from the component and used to
call the RememberLastSearchText method. Although you can also use
the getService method to get one of a component's RDF interfaces (e.g.,
by using
getService(Components.interfaces.nsIRDFDataSource)),
doing so is seldom necessary in practice. RDF components are tailored to the
datasources they represent and usually provide all the access you need to
access that data directly. Example 10-6
lists RDF components in Mozilla.
Example 10-6. RDF-specific components built into Mozilla
@mozilla.org/rdf/container;1
@mozilla.org/rdf/content-sink;1
@mozilla.org/rdf/datasource;1?name=addresscard
@mozilla.org/rdf/datasource;1?name=addressdirectory
@mozilla.org/rdf/datasource;1?name=bookmarks
@mozilla.org/rdf/datasource;1?name=charset-menu
@mozilla.org/rdf/datasource;1?name=composite-
datasource
@mozilla.org/rdf/datasource;1?name=files
@mozilla.org/rdf/datasource;1?name=history
@mozilla.org/rdf/datasource;1?name=httpindex
@mozilla.org/rdf/datasource;1?name=in-memory-
datasource
@mozilla.org/rdf/datasource;1?name=internetsearch
@mozilla.org/rdf/datasource;1?name=ispdefaults
@mozilla.org/rdf/datasource;1?name=local-store
@mozilla.org/rdf/datasource;1?name=localsearch
@mozilla.org/rdf/datasource;1?name=mailnewsfolders
@mozilla.org/rdf/datasource;1?name=msgaccountmanage
r
@mozilla.org/rdf/datasource;1?name=msgfilters
@mozilla.org/rdf/datasource;1?name=msgnotifications
@mozilla.org/rdf/datasource;1?name=smtp
@mozilla.org/rdf/datasource;1?name=subscribe
@mozilla.org/rdf/datasource;1?name=window-mediator
@mozilla.org/rdf/datasource;1?name=xml-datasource
@mozilla.org/rdf/delegate-
factory;1?key=filter&scheme=imap
@mozilla.org/rdf/delegate-
factory;1?key=filter&scheme=mailbox
@mozilla.org/rdf/delegate-
factory;1?key=filter&scheme=news
@mozilla.org/rdf/delegate-
factory;1?key=smtpserver&scheme=smtp
@mozilla.org/rdf/rdf-service;1
@mozilla.org/rdf/resource-factory;1
@mozilla.org/rdf/resource-
factory;1?name=abdirectory
@mozilla.org/rdf/resource-factory;1?name=abmdbcard
@mozilla.org/rdf/resource-
factory;1?name=abmdbdirectory
@mozilla.org/rdf/resource-factory;1?name=imap
@mozilla.org/rdf/resource-factory;1?name=mailbox
@mozilla.org/rdf/resource-factory;1?name=news
@mozilla.org/rdf/xml-parser;1
@mozilla.org/rdf/xml-serializer;1
From this list, components used often in the Mozilla source code include
bookmarks, history, mail and news folders, and address books.
Special URIs
Mozilla's built-in datasource components have special URIs for access. Here
is the format used to determine the URI from the component reference:
Component:
@mozilla.org/rdf/datasource;1?name=SomeName
Datasource URI:
rdf:SomeName
The URI, such as rdf:someName, is also accessible as a datasource property:
foo-ds.URI
10.3.2. What Are RDF Interfaces?
RDF interfaces are interfaces in Mozilla designed to manipulate RDF
structures and data. They typically deal with RDF generally, rather than
specific sets of data (as in the case of components). A common use for an
RDF interface in JavaScript, shown in Example 10-7
, is to use
nsIRDFService to retrieve or assert the root node of an RDF datasource.
Example 10-7. Creating a root node
// get the nsIRDFService interface and assign it to
RDF
RDF = Components.classes[`@mozilla.org/rdf/rdf-
service;1'].
getService(Components.interfaces.nsIRDFService);
// call the GetResource method from the interface
rootResource = RDF.GetResource('urn:root');
Like all Mozilla interfaces, RDF interfaces (shown in Table 10-3
) are
defined in IDL and can be accessed through XPCOM. The examples in this
section use JavaScript and XPConnect to access the components for
simplicity, but you can also use these interfaces with C++, as they are often
in the actual Mozilla source code. Most interfaces deal with datasources,
which drive the use of RDF in Mozilla.
Table 10-3. Mozilla's built-in RDF interfaces
RDF interface Description
nsIRDFService
Mostly used for retrieving
datasources, resources, and literals. It
also registers and unregisters
datasources and resources.
nsIRDFCompositeDataSource
Allows the addition and removal of a
datasource from a composite
RDF interface Description
datasource (which may be empty).
nsIRDFDataSource,
nsIRDFPurgeableDataSource,
nsIRDFRemoteDataSource
Mostly used for adding, removing,
and changing triples in a datasource.
It provides the means to change the
graph.
nsIRDFNode, nsIRDFResource,
nsIRDFLiteral
Provide an equality function. Values
for resources and literals can be
retrieved. Objects of these types are
retrieved from nsIRDFService.
nsIRDFContainer
Provides vector-like access to an
RDF container's elements.
nsIRDFContainerUtils
Provides container creation and other
container-related functions.
nsIRDFObserver
Fires events when data is changed in
a datasource.
nsIRDFXMLParser,
nsIRDFXMLSerializer,
nsIRDFXMLSink,
nsIRDFXMLSource
Used for working with RDF/XML.
Functions are provided for parsing
files and serializing content.
The sheer variety of RDF interfaces may seem overwhelming, but all
interfaces serve different purposes and are often used in conjunction with
one another. In your particular application space, you may find yourself
using some subsets of these interfaces constantly and others not at all. This
section describes some of the most commonly used functions. You can look
up all of interfaces in their entirety at
10.3.3. nsIRDFService
If you will do any sort of RDF processing, you need to use the
nsIRDFService interface. It provides the basics for working with
datasources, resources, and literals, and is useful when you process RDF
data. nsIRDFService can be initialized by using the getService method
of the rdf-service class:
RDF = Components.classes[`@mozilla.org/rdf/rdf-
service;1']
getService(Components.interfaces.nsIRDFService);
Once the service is available, it's ready to go to work. Even though no
datasource is created yet (in this particular example), the RDF service can
still get resources and literals, as shown in the next section.
10.3.3.1. Getting a resource
Once a resource is created (e.g., with the identifier urn:root in Example
10-7), it needs to be added to a datasource:
rootResource = RDF.GetResource('urn:root');
When a resource is already registered under the given identifier (see Section
10.3.3.4, later in this chapter for more information about RDF registration),
then GetResource returns that resource.
10.3.3.2. Getting an anonymous resource
Anonymous resources are resources with no resource identifier. Here is the
creation of a new anonymous resource and a test of its anonymity:
anonResource = RDF.GetAnonymousResource( );
// This would be true. Checking is not necessary,
just here for example.
isAnon = RDF.isAnonymousResource(anonResource);
Typically, these resources are turned into containers, as shown in the next
section. Anonymous resources exist when names are not needed and a
simple reference to that resource is all that is required.
10.3.3.3. Getting a literal
The GetLiteral function returns the given name in the format of a literal,
which you can then use to assert into an RDF graph as a resource.
myName = RDF.GetLiteral('Eric');
Variations on this function are GetIntLiteral and GetDateLiteral.
10.3.3.4. Registering and unregistering datasources
If you create a Mozilla application that uses the same datasource or RDF
resources in different ways, you may want to register the datasource with
Mozilla. When you register a datasource, you register it as a component in
Mozilla (see Section 8.1.6
for more information on Mozilla's component
model), which means it can be accessed and used as easily as any other
XPCOM component, and from anywhere in Mozilla.
To register a datasource, call the RegisterDatasource method of the
RDF Service. In this example, the datasource already exists and is assigned
to a variable named myDatasource:
RDF.RegisterDataSource(myDatasource, false);
In this case, myDatasource is the datasource name, and the false
parameter specifies that this datasource is not replacing a datasource with the
same name. Once a datasource is registered with the component manager in
this way, it can be retrieved by name and associated with another instance:
secondDatasource = anotherRDF.GetDataSource("My
Datasource");
To unregister a datasource from the RDF Service, pass the datasource into
the UnRegisterDataSource function:
RDF.UnRegisterDataSource(myDatasource);
Once it's unregistered, a datasource is no longer available to other instances
of the RDF Service. Registered resources work the same way as datasources
in the RDF Service: if a resource is registered with the RDF Service, then it
is available in every instance of RDF Service. To get two different instances
of the same registered datasource and unregister its use:
newResource = RDF.GetResource('my.resource');
RDF.RegisterResource(newResource,false);
notNewResource = RDF.GetResource('my.resource');
RDF.UnRegisterResource(notNewResource);
If you register resources and datasources, be sure to use the overwrite
Boolean variable on RegisterDataSource and
RegisterResource to avoid overwriting existing datasources.
10.3.3.5. Getting a remote datasource
Finally, nsIRDFService provides a useful method that loads a datasource
from a remote server, which is a process that occurs asynchronously.
Compared to forthcoming discussions about datasource loading,
GetDataSource is a real shortcut:
remoteDatasource =
RDF.GetDataSource(' />');
Remember that RDF files requested in this way must be set with the
text/rdf MIME type on the web server to load properly.
10.3.4. nsIRDFCompositeDataSource
When you work with multiple datasources, you can make things easier by
grouping them, which nsIRDFCompositeDataSource allows you to do. This
functionality aggregates data in a number of Mozilla's applications. To get
this interface, invoke:
composite_datasource
= '@mozilla.org/rdf/datasource;1?name=composite-
datasource';
compDataSource =
Components.classes[composite_datasource]
getService(Components.interfaces.nsIRDFCompositeDat
aSource);
Once you have the interface, adding and removing datasources from the
composite is easy. You can also enumerate the datasources by using the
getNext method. Example 10-8
demonstrates how to add, remove, and
cycle through datasources.
Example 10-8. Manipulating datasources
compDataSource.AddDataSource(datasource1);
compDataSource.AddDataSource(datasource2);
compDataSource.AddDataSource(datasource3);
compDataSource.RemoveDataSource(datasource1);
allDataSources = compDataSource.GetDataSources( );
datasource2 = allDataSources.getNext( );
datasource2.QueryInterface(Components.interfaces.ns
IRDFDataSource);
datasource3 = allDataSources.getNext( );
datasource3.QueryInterface(Components.interfaces.ns
IRDFDataSource);
In Example 10-8
, allDataSources is an nsISimpleEnumerator returned
by the GetDataSources method on the composite datasource.
datasource1 is removed from the composite, and then the remaining
datasources are cycled through. This step provides a way to iterate through a
collection of datasources. nsIRDFCompositeDatasource also inherits the
many functions of nsIRDFDataSource; refer to the section Section 10.3.5
for more information.
10.3.5. nsIRDFDataSource
The nsIRDFDataSource interface is large, with twenty functions and one
attribute (URI), so it's one of the most common interfaces used to
manipulate RDF data. nsIRDFDataSource contains all the components in
Example 10-6
with "datasource" in their contract IDs, along with other
common components:
@mozilla.org/browser/bookmarks-service;1
@mozilla.org/related-links-handler;1
@mozilla.org/browser/localsearch-service;1
@mozilla.org/registry-viewer;1
@mozilla.org/browser/global-history;1
The nsIRDFDataSource interface is meant to handle some of the core
interaction with the datasource. APIs such as URI, GetTarget, Assert,
and Change are helpful for working on the RDF graph itself. For example,
the @mozilla.org/rdf/datasource;1?name=in-memory-
datasource RDF component demonstrates the use of the
nsIRDFDataSource interface. When this component is created, it's a blank
datasource in memory, into which objects are inserted, changed, and
removed. You can access the nsIRDFDataSource interface from the RDF
component by first constructing an RDF graph in the in-memory datasource:
mem = '@mozilla.org/rdf/datasource;1?name=in-
memory-datasource';
datasource = Components.classes[mem].
createInstance(Components.interfaces.nsIRDFDataSour
ce);
Of the twenty functions (found at
in this interface, we show only a handful here:
• Assertion and removal
• Changing values
• Moving triples
• HasAssertion
• GetTarget
• GetSource
The main purpose of the nsIRDFDatasource interface is to work with RDF
triples inside a datasource, allowing you to change that datasource's RDF
graph.
10.3.5.1. Assertion and removal
Recall from the Section 10.1.1.2
section, earlier in this chapter, that triples
are RDF statements in which the relationship between the subject, predicate,
and object is more strictly defined. In the interface code, a triple's elements
are all typically defined as resources rather than plain URIs, which means
they can be asserted into a datasource in the particular sequence that makes
them meaningful as parts of a triple:
rootSubject = RDF.GetResource('urn:root');
predicate =
RDF.GetResource(' />rs');
object = RDF.GetResource('Chapter1');
datasource.Assert(rootSubject,predicate,object,true
);
Once you assert the statement's elements into the datasource in this way, the
datasource contains the triple. The truth value parameter in the last slot
indicates that the given node is "locked" and thus cannot be overwritten.
Removing a triple from the datasource is as easy as adding it. If you try to
remove a triple that doesn't exist, your request is ignored and no error
messages are raised. To unassert a triple in the datasource, use:
rootSubject = RDF.GetResource('urn:root');
predicate =
RDF.GetResource(' />rs');
object = RDF.GetResource('Chapter8');
datasource.Unassert(rootSubject,predicate,object);
10.3.5.2. Changing values
Changing values in a datasource is also very easy. Assert and change a
literal in the datasource as follows:
subject = RDF.GetResource('Chapter1');
predicate =
RDF.GetResource(' />);
object = RDF.GetLiteral('Mozilla as a Platform');
datasource.Assert(subject,predicate,object,true);
newObject = RDF.GetLiteral('Mozilla is a cool
Platform!');
datasource.Change(subject,predicate,newObject,);
If working with triples seems hard in the template generation, their use in
these examples where adding to and changing the parts is so easy may
make things clearer.
10.3.5.3. Moving triples
Moving a triple in a datasource also requires some simple code. This
example moves the asserted triple in the previous section:
newSubject = RDF.GetResource('Chapter99');
// Moving from Chapter1 to Chapter99
datasource.Move(subject,newSubject,predicate,object
);
10.3.5.4. HasAssertion
This next example checks if the previous statement still exists in the
datasource.
datasource.HasAssertion(newSubject,predicate,object
,true);
This function is useful when you create new statements and resources and
want to make sure you are not overwriting pre-existing resources.
10.3.5.5. GetTarget
The GetTarget method returns the resource's property value (i.e., the
object). Given the RDF statement "(Eric) wrote (a book)," for example, the
GetTarget method would input "Eric" and "wrote" and get back the
object "a book." Once again, the example code is based on the previous
examples:
object =
datasource.GetTarget(newSubject,predicate,true);
objects =
datasource.GetTargets(rootSubject,predicate,true);
// objects is an nsIEnumeration of the object and
its properties
In addition to GetTarget, as seen above, a GetTargets function returns
an object and its properties in an enumeration. This function can be very
handy for quick access to resources with fewer function calls.
10.3.5.6. GetSource
GetSource is the inverse of GetTarget. Whereas GetTarget returns
an object, GetSource returns the subject attached to an object. Given the
RDF statement "(Eric) wrote (a book)" again, in other words, the
GetSource method would input "wrote" and "a book" and get back the
statement subject "Eric."
subject =
datasource.GetSource(object,predicate,true);
subjects =
datasource.GetSources(object,predicate,true);
// subjects is an nsIEnumeration of the subject and
its properties