Chapter 10. RDF, RDF Tools, and the Content Model-P4
When you create RDF statements with assertions or work with in-memory
datasources, it is often difficult to remember the shape of the graph, which
statements exist about which resources, or which objects are attached to
which subjects. These "getter" methods can help you verify the shape of
your graph.
10.3.6. nsIRDFRemoteDataSource
The Section 10.3.3
section (earlier in this chapter) showed how to load a
datasource from a remote server simply. If you want control over that
datasource, you can manage it by using the nsIRDFRemoteDatasource to set
up a remote datasource:
xml = '@mozilla.org/rdf/datasource;1?name=xml-
datasource';
datasource = Components.classes[xml].
createInstance(Components.interfaces.nsIRDFRemoteDa
taSource);
datasource.Init(' />;
datasource.Refresh(false);
In this example, the Init and Refresh methods control the datasource on
the server. In addition to these methods, you can call the Flush method to
flush the data that's been changed and reload, or you can check whether the
datasource is loaded by using the loaded property:
if (datasource.loaded) {
// Do something
}
Built-in datasources that implement nsIRDFRemoteDataSource (and other
necessary interfaces) and do their own data handling include:
@mozilla.org/rdf/datasource;1?name=history
nsIRDFDataSource.GetSource
nsIRDFDataSource.GetTarget
nsIRDFNode is the parent of nsIRDFResource and nsIRDFLiteral. It is not
used often because it's sole function is to test equality:
isEqual = resource1.EqualsNode(resource2);
The other two interfaces inherit this function automatically. EqualsNode
tests the equivalency of two resources, which can be useful when you try to
put together different statements (e.g., "Eric wrote a book" and "[This] book
is about XML") and want to verify that a resource like "book" is the same in
both cases.
10.3.8.1. nsIRDFResource
Like nsIRDFNode, nsIRDFResource is a minimalist interface. Here are the
functions and the property available in a resource from the nsIRDFResource
interface:
resource = RDF.GetAnonymousResource( );
// get the resource value, something like
'rdf:#$44RG7'
resourceIdentifierString = resource.Value;
// compare the resource to an identifier
isTrue =
resourceEqualsString(resourceIdentifierString);
// Give the resource a real name.
resource.Init('Eric');
10.3.8.2. nsIRDFLiteral
A literal's value can be read but not written. To change the value of a literal,
make a new literal and set it properly:
aValue = literal.Value;
Note that aValue could be a string or an integer in this case. The base type
conversion, based on the data's format, is done automatically.
10.3.9. nsIRDFContainerUtils
resource, their data types are different. isContainer, isSequence, and
isEmpty can be used more easily with other RDF functions when a
resource is used as a parameter:
object =
datasource.GetTarget(subject,predicate,true);
if(RDF.isAnonymousResource(object))
{
isSeq = containerUtils.IsSeq(datasource,object);
}
The RDF container utilities also provide an indexing function. indexOf is
useful for checking if an element exists in a container resource:
indexNumber =
containerUtils.indexOf(datasource,object,RDF.GetLit
eral('Eric'));
if(index != -1)
alert('Eric exists in this container');
10.3.10. nsIRDFContainer
This interface provides vector-like access to an RDF container's elements.[1]
The nsIRDFContainer interface allows you to add, look up, and remove
elements from a container once you create it.
10.3.10.1. Adding an element to a container
You can add an element to a container in two ways. You can append it to the
end of the list with Append or insert it at a specific place in the container:
newLiteral = RDF.GetLiteral('Ian');
aSequence.AppendElement(newLiteral);
// or
aSequence.InsertElementAt(newLiteral,3,true);
The second attribute in InsertElementAt is where the element should
manner. See the section Section 10.5
, later in this chapter, for more
information.
10.3.11.1. nsIRDFXMLParser and nsIRDFXMLSink
nsIRDFXML is the raw RDF/XML parser of Mozilla. Used by Mozilla, its
main purpose is to parse an RDF file asynchronously as a stream listener.
Though this subject is beyond the scope of this book, the interface provides
something interesting and useful. The parseString function allows you
to feed nsIRDFXMLParser a string and have it parse that data as RDF and
put it into a datasource, as Example 10-9
demonstrates.
Example 10-9. Parse an RDF/XML string into a datasource
RDF = Components.classes['@mozilla.org/rdf/rdf-
service;1'].
getService(Components.interfaces.nsIRDFService);
// Used to create a URI below
ios = Components.classes["@mozilla.org/network/io-
service;1"].
getService(Components.interfaces.nsIIOService);
xmlParser = '@mozilla.org/rdf/xml-parser;1';
parser = Components.classes[xmlParser].
createInstance(Components.interfaces.nsIRDFXMLParse
r);
uri = ios.newURI("
null);
// Entire RDF File stored in a string
rdfString =
}
};
Once the event handlers are set up, you can use nsIRDFXMLSink:
sink =
datasource.QueryInterface(Components.interfaces.nsI
RDFXMLSink);
sink.addXMLSinkObserver(observer);
The events are then triggered automatically when the datasource is loaded up
with data, allowing you to create handlers that manipulate the data as it
appears.
10.3.11.2. nsIRDFXMLSerializer and nsIRDFXMLSource
These two interfaces are meant to work together. nsIRDFXMLSerializer lets
you init a datasource into the xml-serializer module that outputs
RDF. However, nsIRDFXMLSource actually contains the Serialize
function. Here's how to serialize a datasource into an alert:
serializer = '@mozilla.org/rdf/xml-serializer;1';
s = Components.classes[serializer].
createInstance(Components.interfaces.nsIRDFXMLSeria
lizer);
s.init(datasource);
output = new Object( );
output.write = new function(buf,count)
{
alert(buf); // Show the serialized syntax
return count;
}
s.QueryInterface(Components.interfaces.nsIRDFXMLSou
rce).Serialize(output);
As in the previous example with nsIRDFXMLParser, Example 10-10
hardware information (e.g., "Eric uses a Compaq with the serial number
1223456-1091 to write his book and he sits on the fourth floor of the Acme
Building, which is the Bay Area branch of Acme Enterprises.)
10.4.1. Template Dynamics in XBL
Putting templates inside XBL can be a useful organizational scheme. Here is
a basic implementation of a widget that creates a list of people based on
names listed in an attribute:
<people names="Brian King,Eric Murphy,Ian
Oeschger,Pete Collins,David Boswell"/>
Obviously, the comma is used as the delimiter for this list. The constructor
element in Example 10-11
uses JavaScript to break up this string.
Example 10-11. Binding with in-memory datasource and <listbox>
template
<?xml version="1.0"?>
<bindings xmlns ="
xmlns:xul=" />per/there.is.only.xul">
<binding id="people">
<implementation>
<constructor>
<![CDATA[
// Read the Names into an Array
names =
document.getAnonymousNodes(this)[0].getAttribute('n
ames');
names = new String(names);
namesArray= names.split(',');
// Initialize the RDF Service
rdf = Components
.classes['@mozilla.org/rdf/rdf-
of people
peopleSequence = rdfc.MakeSeq(datasource,
people);
for(i=0;i<namesArray.length;i++)
{
// Create a Person, with a Unique Number,
for example
person = rdf.GetResource(i);
// Insert the Person's name into the RDF
graph underneath number
datasource.Assert
(person,
rdf.GetResource('
rdf.GetLiteral(namesArray[i]),true);
peopleSequence.AppendElement(person);
}
list = document.getAnonymousNodes(this)[1];
list.database.AddDataSource(datasource);
]]>
</constructor>
</implementation>
<content>
<xul:box id="names" inherits="names"
flex="0"/>
<xul:listbox datasources="rdf:null"
ref="urn:root" flex="1">
<xul:template>
<xul:rule>
<xul:conditions>