RDF in Mozilla FAQ

  • Revision slug: RDF_in_Mozilla_FAQ
  • Revision title: RDF in Mozilla FAQ
  • Revision id: 111866
  • Created:
  • Creator: Andreas Wuest
  • Is current revision? No
  • Comment

Revision Content

General

Where do I start?

RDF serves two primary purposes in Mozilla. First, it is a simple, cross-platform database for small data stores. Second, and more importantly, the RDF model is used along with XUL templates as an abstract "API" for displaying information. RDF in Fifty Words or Less is a quick, high-level description of what RDF does in Mozilla. The RDF Back-end Architecture document describes in more detail how Mozilla's RDF implementation works, and gives a quick overview of the interfaces that are involved.

Where do I find information on Open Directory ("dmoz")?

Unfortunately, not here! Well, here's a little... Start at http://www.dmoz.org/ for more information on the Open Directory. The Open Directory dataset is available as a (huge) RDF/XML dump. It describes thousands of Web sites using a mix of the Dublin Core metadata vocabulary and the DMoz taxonomy. See their RDF pages for more information, or odp-rdf-announce for updates relating to their exact data format. The ChefMoz site (collaborative restaurant guide) is also available in RDF.

If you have problems with the DMoz and ChefMoz data, it's best to contact those projects directly. But if you do something interesting with this content (eg. have Mozilla use it, eg. by loading chunks of it into a XUL UI from a remote site), don't forget to let mozilla-rdf and the RDF Interest Group lists know. Those lists would probably also be interested in tools for cleaning / re-processing / storing the DMoz data too. See the sites using ODP data pages for some directories based on the ODP RDF dumps.

What is a datasource?

RDF can generally be viewed in two ways: either as a graph with nodes and arcs, or as a "soup" of logical statements. A datasource is a subgraph (or collection of statements, depending on your viewpoint) that are for some reason collected together. Some examples of datasources that exist today are "browser bookmarks", "browser global history", "IMAP mail accounts", "NNTP news servers", and "RDF/XML files".

In Mozilla, datasources can be composed together using the composite data source. This is like overlaying graphs, or merging collections of statements ("microtheories") together. Statements about the same RDF resource can then be intermingled: for example, the "last visit date" of a particular website comes from the "browser global history" datasource, and the "shortcut keyword" that you can type to reach that website comes from the "browser bookmarks" datasource. Both datasources refer to "website" by URL: this is the "key" that allows the datasources to be "merged" effectively.

For a more detailed account of how to write a datasource, refer to the RDF Datasource How-To.

How does Mozilla manage datasources?

The RDF service manages a table of all loaded datasources. The table is keyed by the datasource's "URI", which is either the URL of an RDF/XML file, or a "special" URI starting with rdf: that refers to a built-in datasource.

Datasources may be loaded via the RDF service using the GetDataSource() method. If the URI argument refers to an RDF/XML file's URL, then the RDF service will create an RDF/XML datasource and asynchronously parse it. The datasource will remain "cached" until the last reference to the datasource is released.

If the URI argument refers to a built-in datasource, the RDF service will use the XPCOM Component Manager to load a component whose ContractID is constructed using the "special" URI and the well-known prefix@mozilla.org/rdf/datasource;1?name=</code>.

For example,

rdf:foo

Would load:

@mozilla.org/rdf/datasource;1?name=foo

As with RDF/XML datasources, a datasource that is retrieved this way is "cached" by the RDF service until the last reference is dropped.

How do I create a datasource from an RDF/XML file?

You can either create an RDF/XML datasource using the RDF service's GetDataSource() method:

// Get the RDF service
var RDF =
  Components
  .classes["@mozilla.org/rdf/rdf-service;1"]
  .getService(Components.interfaces.nsIRDFService);
// ...and from it, get the datasource. Make sure that your web server
// dishes it up as text/xml (recommended) or text/rdf!
var ds = RDF.GetDataSource("http://www.mozilla.org/some-rdf-file.rdf");
// Note that ds will load asynchronously, so assertions will not
// be immediately available

Alternatively, you can create one directly using the XPCOM Component Manager, as the following code fragment illustrates:

// Create an RDF/XML datasource using the XPCOM Component Manager
var ds =
  Components
  .classes["@mozilla.org/rdf/datasource;1?name=xml-datasource"]
  .createInstance(Components.interfaces.nsIRDFDataSource);
// The nsIRDFRemoteDataSource interface has the interfaces
// that we need to setup the datasource.
var remote =
   ds.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource);
// Be sure that your web server will deliver this as text/xml (recommended) or text/rdf!
remote.Init("http://www.mozilla.org/some-rdf-file.rdf");
// Make it load! Note that this will happen asynchronously. By setting
// aBlocking to true, we could force it to be synchronous, but this
// is generally a bad idea, because your UI will completely lock up!
remote.Refresh(false);
// Note that ds will load asynchronously, so assertions will not
// be immediately available

You may decide that you need to "manually" create an RDF/XML datasource if you want to force it to load synchronously.

How do I reload an RDF/XML datasource?

You can force an RDF/XML datasource (or any datasource that supports nsIRDFRemoteDataSource) using Refresh() method of nsIRDFRemoteDataSource. Refresh() takes a single parameter that indicates whether you'd like it to perform its operation synchronously ("blocking") or asynchrounously ("non-blocking"). You should never do a synchronous load unless you really know what you're doing: this will freeze the UI until the load completes!

How can I tell if an RDF/XML datasource has loaded?

Using the nsIRDFRemoteDataSource interface, it is possible to immediately query the loaded property to determine if the datasource has loaded or not:

// Get the RDF service
var RDF =
  Components
  .classes["@mozilla.org/rdf/rdf-service;1"]
  .getService(Components.interfaces.nsIRDFService);
// Get the datasource.
var ds = RDF.GetDataSource("http://www.mozilla.org/some-rdf-file.rdf");
// Now see if it's loaded or not...
var remote =
  ds.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource);

if (remote.loaded) {
  alert("the datasource was already loaded!");
}
else {
  alert("the datasource wasn't loaded, but it's loading now!");
}

Say the datasource wasn't loaded, and is loading asynchronously. Using this API and JavaScript's setTimeout(), one could set up a polling loop that would continually check the loaded property. This is kludgy, and even worse, won't detect a failed load, for example, because there wasn't any data at the URL!

For this reason, there is an observer interface that allows you to spy on a datasource's progress. The following code illustrates its usage:

// This is the object that will observe the RDF/XML load's progress
var Observer = {
  onBeginLoad: function(aSink)
    {},

  onInterrupt: function(aSink)
    {},

  onResume: function(aSink)
    {},

  onEndLoad: function(aSink)
    { alert("done!"); },

  onError: function(aSink, aStatus, aErrorMsg)
    { alert("error! " + aErrorMsg); }
};
// Get the RDF service
var RDF =
  Components
  .classes["@mozilla.org/rdf/rdf-service;1"]
  .getService(Components.interfaces.nsIRDFService);
// Get the datasource.
var ds = RDF.GetDataSource("http://www.mozilla.org/some-rdf-file.rdf");
// Now see if it's loaded or not...
var remote =
  ds.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource);

if (remote.loaded) {
  alert("the datasource was already loaded!");
}
else {
  alert("the datasource wasn't loaded, but it's loading now!");
  // RDF/XML Datasources are all nsIRDFXMLSinks
  var sink =
    ds.QueryInterface(Components.interfaces.nsIRDFXMLSink);
  // Attach the observer to the datasource-as-sink
  sink.addXMLSinkObserver(Observer);
  // Now Observer's methods will be called-back as
  // the load progresses.
}

Note that the observer will remain attached to the RDF/XML datasource unless removeXMLSinkObserver is called.

How do I access the information in a datasource?

The nsIRDFDataSource interface is the means by which you access and manipulate the assertions in a datasource.

  • boolean HasAssertion(aSource, aProperty, aTarget, aTruthValue).
    This tests the datasource to see if it has the specified tuple.
  • nsIRDFNode GetTarget(aSource, aProperty, aTruthValue).
  • nsISimpleEnumerator GetTargets(aSource, aProperty, aTruthValue).
  • nsIRDFResource GetSource(aProperty, aTarget, aTruthValue).
  • nsISimpleEnumerator GetSoruces(aProperty, aTarget, aTruthValue).
  • nsISimpleEnumerator ArcLabelsIn(aTarget).
  • nsISimpleEnumerator ArcLabelsOut(aSource).

You can also use the RDF container interfaces to access information contained in RDF containers.

How do I change information in the datasource?

How do I save changes to an RDF/XML datasource back?

An RDF/XML datasource can be QueryInterface()'d to nsIRDFRemoteDataSource. This interface has a Flush() method, which will attempt to write the contents of the datasource back to the URL from which they were loaded, using a protocol specific mechanism (e.g., a file: URL just writes the file; an http: URL might do an HTTP-POST). Flush() only writes the datasource if its contents have changed.

How do I merge two or more datasources to view them as one?

How do I access "built-in" datasources?

A built-in datasource is a locally-installed component that implements nsIRDFDataSource. For example, the bookmarks service. First, check here to make sure you will be allowed to access a built-in datasource. There are several security restrictions on accessing built-in datasources from "untrusted" XUL and JS.

Since a built-in datasource is just an XPCOM component, you can instantiate it directly using the XPConnect component manager.

// Use the component manager to get the bookmarks service
var bookmarks =
  Components.
  classes["@mozilla.org/rdf/datasource;1?name=bookmarks"].
  getService(Components.interfaces.nsIRDFDataSource);

// Now do something interesting with it...
if (bookmarks.HasAssertion(
     RDF.GetResource("http://home.netscape.com/NC-rdf#BookmarksRoot"),
     RDF.GetResource("http://home.netscape.com/NC-rdf#child"),
     RDF.GetResource("http://home.netscape.com/NC-rdf#PersonalToolbarFolder"),
     true) {
  // ...
}

Alternatively, some datasources have "special" RDF-friendly ContractIDs that make it easy to instantiate the datasource using either the nsIRDFSerivce's GetDataSource() method or the datasources attribute on a XUL template. These ContractIDs are of the form

@mozilla.org/rdf/datasource;1?name=name

And are accessable via GetDataSource() and the datasources attribute using the shorthand rdf:name. For example, the following XUL fragment illustrates how to add the bookmarks service as a datasource into a XUL template.

<tree datasources="rdf:bookmarks">
  ...
</tree>

How do I manipulate RDF "containers"?

To manipulate an RDF "container" (an <rdf:Seq>, for example), you can use nsIRDFContainerUtils which can be instantiated as a service with the following ContractID:

@mozilla.org/rdf/container-utils;1

You can use this service to detect if something is an RDF container using IsSeq(), IsBag(), and IsAlt(). You can "make a resource into a container" if it isn't one already using MakeSeq(), MakeBag(), or MakeAlt(). These methods return an nsIRDFContainer which allows you to do container-like operations without getting your hands too dirty.

Alternatively, if your datasource already has an object that is an RDF container, you can instantiate an nsIRDFContainer object with the

@mozilla.org/rdf/container;1

ContractID and Init() it with the datasource and resource as parameters. Note that this will fail if the resource isn't already a container.

XUL Templates

XUL templates are created by specifying a datsources attribute on an element in a XUL document.

There are two "forms" that XUL templates may be written in. The "simple" form, which is currently the most common form in the Mozilla codebase, and the "extended" form, which allows for sophisticated pattern matching against the RDF graph. See the XUL:Template Guide. (These are bizarrely arranged because the eventual intent is to introduce templates using the extended form -- which in many ways is conceptually simpler, even if more verbose -- and then treat the "simple" form as a shorthand for the extended form.)

What can I build with a XUL template?

You can build any kind of content using a XUL template. You may use any kind of tag (including HTML, or arbitrary XML) in the <action> section of a <rule>.

When should I use a XUL template?

One alternative to using RDF and XUL templates is to use the W3C DOM APIs to build up and manipulate a XUL (or HTML) content model. There are times, however, when doing so may be inconvenient:

  1. There are several "views" of the data. For example, Mozilla mail/news reveals the folder hierarchy in the toolbar, the "folder pane", in several menus, and in some of the dialogs. Rather than writing three pieces of JS (or C++) code to construct the DOM trees each for <menubutton>, <menu>, and <tree> content models, you write three compact sets of rules for each content model.
  2. The data can change. For example, a mail/news user may add or remove IMAP folders. (Note how this requirement complicates the task of building a content model!) The XUL template builder uses the rules to automatically keep all content models in sync with your changes.

In order to take advantage of this functionality, you must of course be able to express your information in terms of the RDF datasource API, either by using the built-in memory datasource, using RDF/XML to store your information, or writing your own implementation (possibly in JavaScript) of nsIRDFDataSource.

What gets loaded when I specify "datasources="

The datasources attribute on the "root" of a template specifies a whitespace-separated list of datasource URIs to load. But what is a "datasource URI"? It is either:

  • An abbreviated ContractID for a locally installed component. By specifying rdf:name, you instruct the template builder to load the XPCOM component with the ContractID @mozilla.org/rdf/datasource;1?name=name.
  • The URL of an RDF/XML file. For example,
    file:///tmp/foo.rdf
    chrome://mycomponent/content/component-data.rdf
    http://www.mysite.com/generate-rdf.cgi
    ftp://ftp.somewhere.org/toc.rdf
    

    The load will be processed asynchronously, and as RDF/XML arrives, the template builder will generate content.

In either case, the datasource will be loaded using the nsIRDFService's GetDataSource() method, so it will be managed similarly to all other datasources loaded this way.

What is the security model for RDF/XML in XUL?

XUL that is loaded from a "trusted" URL (currently, any chrome: URL) can specify any datasource URI in the datasources attribute of the XUL template.

XUL that is loaded from an "untrusted" URL can only specify an RDF/XML document from the same codebase (in the Java sense of the word) that the XUL document originated from. No "special" (i.e., rdf:) datasources may be loaded from untrusted XUL.

How do I add a datasource to a XUL template?

Although it's possible to create a XUL template with an "implicit" set of datasources by specifying the datasources attribute, there are often times when you won't know the datasource that you want to add until after the XUL is loaded. For example, your XUL may need compute the datasources that it wants to display in an onload handler. Or, it may need to add a datasource later based on some user action.

Here's a simple example that illustrates how to do this. Let's start with the following XUL.

<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  ...
  <tree id="my-tree" datasources="rdf:null">
    ...
  </tree>
  ...
</window>

Assuming that we've aquired a datasource somehow (e.g., like this), the following sample code illustrates how to add that datasource to the template, and then force the template to rebuild itself based on the newly added datasource's contents.

var ds = /* assume we got this somehow! */;
// Get the DOM element for 'my-tree'
var tree = document.getElementById('my-tree');
// Add our datasource to it
tree.database.AddDataSource(ds);
// Force the tree to rebuild *now*. You have to do this "manually"!
tree.builder.rebuild();

Any XUL element with a datasources attribute will "get" a database property and a builder property. The database property refers to an nsIRDFCompositeDataSource object, which is contains the datasources from which the template is built.

The builder property refers to an nsIXULTemplateBuilder object, which is a the "builder" that maintains the state of the template's contents.

Note the rdf:null datasource: this is a special datasource that says, "hey, I don't have a datasource for you yet, but I'm going to add one later, so set yourself up for it!" It causes the database and builder properties to get installed, but leaves the database empty of datasources: you've got to add these in yourself!

Can I manipulate a XUL template using the DOM APIs?

Yes: you can add rules, remove rules, change a rule's conditions, and change the content that is built by a rule. In fact, you can change anything about a template using the W3C DOM APIs.

The only caveat is that you must call rebuild() before the changes you've made will take effect (just as you must if you add a datasource to the XUL template).

How do I insert plaintext from a template?

To insert plaintext in a template, use the <text> element.

<template>
  <rule>
    <conditions>...</condition>
    <bindings>...</bindings>
    <action>
      <text value="?some-variable" />
    </action>
  </rule>
</template>

The above template will create a content model that runs a series of text nodes together.

Troubleshooting

Tricks and tips from the field.

My RDF/XML file won't load.

The most common cause for RDF/XML not to load from a web server is incorrect MIME type. Make sure your server is delivering the file as text/xml (recommended) or text/rdf (bogus).

Note that the W3C RDF Core WG are registering application/rdf+xml, though this isn't understood by any Mozilla code yet. (do we have a bug registered to track this? -- danbri)

Another possible problem: for remotely-loaded XUL and RDF, you might need to adjust Mozilla's security restrictions (see belowfor example code). If XUL isn't loading your RDF, and the mimetype is OK, this could well be your problem.

You can use the rdfcat and rdfpoll utilities to verify that the RDF/XML is actually valid. Both of these programs are built by default on Windows, and on Linux when the configure --enable-tests is specified.

  • rdfcat url
    Takes as a parameter a URL from which to read an RDF/XML file, and will "cat" the file back to the console. You can use it to verify that the RDF/XML that you've written is being properly parsed by Mozilla.
  • rdfpoll url {{mediawiki.external('<i>interval</i>')}}
    Takes as a parameter a URL from which to read an RDF/XML file. It also accepts an optional poll interval, where it will re-load the URL. It outputs the assertions that are generated from each load. Note that a polling reload generates a set of differences between the current and previous contents of the RDF/XML file. This is useful for debugging generated RDF/XML that may change over time.

Both these programs are slow to load and run (but they will run, eventually). They initialize XPCOM and bring up Necko to be able to load and process URLs just like Mozilla does.

Nothing happens after I call AddDataSource.

Note that the template builder will not rebuild the contents of a template automatically after AddDataSource or RemoveDataSource have been called on the builder's database. To refresh the template's contents, you must manually call elt.builder.rebuild() yourself.

Why? This was done to avoid multiple rebuilds when more than one datasource is added to the database.

Examples

Where can I find some (working) examples?

A few examples are posted here. Some of these are included in signed scripts, and are runnable from HTTP directly.

See also duplicates.rdf (for live RDF feed from Mozilla) alongside duplicates.xul. Note that for these to work, you have to relax Mozilla's security model. To do this, add the following line to your preferences file. (Shut down Mozilla first since it overwrites your preferences file when you quit.)

user_pref("signed.applets.codebase_principal_support", true);

Mozilla will ask you if you want to grant the scripts in duplicates.xul permission to access XPConnect; respond in the affirmative.

Currently, Mozilla does not allow unprivileged access to the RDF interfaces and services; see bug 122846 for details.

Please mail danbri, mozilla-rdf or waterson with URLs if you are aware of other examples to which we ought to link!

Notes

  1. See also W3C RDF and Semantic Web pages for more information on RDF and related technologies.

Contributors

  • Examples section added 2002-07-02 by danbri </li>
  • Thanks to Myk Melez for notes on remote XUL / security policy

Author: Chris Waterson

Original Document Information

Revision Source

<p>
</p>
<h2 name="General">General</h2>
<h3 name="Where_do_I_start.3F">Where do I start?</h3>
<p><a href="en/RDF">RDF</a> serves two primary purposes in Mozilla. First, it is a simple,
cross-platform database for small data stores. Second, and more
importantly, the RDF model is used along with <a href="en/XUL/Template_Guide">XUL templates</a> as an abstract "API" for displaying information. <a href="en/RDF_in_Fifty_Words_or_Less_(external)">RDF in Fifty Words or Less</a> is a quick, high-level description of what RDF does in Mozilla. The <a href="en/RDF_Back-end_Architecture_(external)">RDF Back-end Architecture</a> document describes in more detail how Mozilla's RDF implementation
works, and gives a quick overview of the interfaces that are
involved.
</p>
<h3 name="Where_do_I_find_information_on_Open_Directory_.28.22dmoz.22.29.3F">Where do I find information on Open Directory ("dmoz")?</h3>
<p>Unfortunately, <em>not here</em>! Well, here's a little... Start at http://www.dmoz.org/ for more information on the Open Directory. The Open Directory
dataset is available as a (huge) RDF/XML dump. It describes
thousands of Web sites using a mix of the <a class="external" href="http://www.dublincore.org/">Dublin Core</a> metadata vocabulary and the DMoz taxonomy. See <a class="external" href="http://dmoz.org/rdf.html">their RDF pages</a> for more information, or <a class="external" href="http://groups.yahoo.com/group/odp-rdf-announce/">odp-rdf-announce</a> for updates relating to their exact data format.  The <a class="external" href="http://chefmoz.org/">ChefMoz</a> site (collaborative restaurant guide) is also <a class="external" href="http://chefmoz.org/rdf.html">available in RDF</a>.
</p><p>If you have problems with the DMoz and ChefMoz data, it's best to
contact those projects directly.  But if you do something
interesting with this content (eg. have Mozilla use it, eg. by
loading chunks of it into a XUL UI from a remote site), don't
forget to let <a class="external" href="mailto:mozilla-rdf@mozilla.org">mozilla-rdf</a> and the <a class="external" href="mailto:www-rdf-interest@w3.org">RDF Interest Group</a> lists know. Those lists would probably also be interested in tools
for cleaning / re-processing / storing the DMoz data too. See the <a class="external" href="http://dmoz.org/Computers/Internet/Searching/Directories/Open_Directory_Project/Use_of_ODP_Data/">sites using ODP data</a> pages for some directories based on the ODP RDF dumps.
</p>
<h3 name="What_is_a_datasource.3F">What is a datasource?</h3>
<p>RDF can generally be viewed in two ways: either as a graph with
nodes and arcs, or as a "soup" of logical statements. A datasource
is a subgraph (or collection of statements, depending on your
viewpoint) that are for some reason collected together. Some
examples of datasources that exist today are "browser bookmarks",
"browser global history", "IMAP mail accounts", "NNTP news
servers", and "RDF/XML files".
</p><p>In Mozilla, datasources can be <em>composed</em> together using the <a class="external" href="http://lxr.mozilla.org/mozilla/source/rdf/base/idl/nsIRDFCompositeDataSource.idl">composite data source</a>. This is like overlaying graphs, or merging collections of statements
("microtheories") together. Statements about the same RDF
<em>resource</em> can then be intermingled: for example, the "last
visit date" of a particular website comes from the "browser global
history" datasource, and the "shortcut keyword" that you can type
to reach that website comes from the "browser bookmarks"
datasource. Both datasources refer to "website" by URL: this is the
"key" that allows the datasources to be "merged" effectively.
</p><p>For a more detailed account of how to <em>write</em> a datasource,
refer to the <a href="en/RDF_Datasource_How-To_(external)">RDF Datasource How-To</a>.
</p>
<h3 name="How_does_Mozilla_manage_datasources.3F">How does Mozilla manage datasources?</h3>
<p>The <a class="external" href="http://lxr.mozilla.org/mozilla/source/rdf/base/idl/nsIRDFService.idl">RDF service</a> manages a table of all loaded datasources. The table is keyed by
the datasource's "URI", which is either the URL of an RDF/XML file,
or a "special" URI starting with <code>rdf:</code> that refers to a
built-in datasource.
</p><p>Datasources may be loaded via the RDF service using the
<code>GetDataSource()</code> method. If the URI argument refers to
an RDF/XML file's URL, then the RDF service will create
an <em>RDF/XML datasource</em> and asynchronously parse it. The
datasource will remain "cached" until the last reference to the
datasource is released.
</p><p>If the URI argument refers to a built-in datasource, the RDF
service will use the XPCOM <em>Component Manager</em> to load a
component whose <em>ContractID</em> is constructed using the
"special" URI and the well-known prefix@mozilla.org/rdf/datasource;1?name=&lt;/code&gt;.
</p><p>For example,
</p>
<pre class="eval">rdf:foo
</pre>
<p>Would load:
</p>
<pre class="eval">@mozilla.org/rdf/datasource;1?name=foo
</pre>
<p>As with RDF/XML datasources, a datasource that is retrieved this
way is "cached" by the RDF service until the last reference is
dropped.
</p>
<h3 name="How_do_I_create_a_datasource_from_an_RDF.2FXML_file.3F">How do I create a datasource from an RDF/XML file?</h3>
<p>You can either create an RDF/XML datasource using the <a class="external" href="http://lxr.mozilla.org/mozilla/source/rdf/base/idl/nsIRDFService.idl">RDF service</a>'s <code>GetDataSource()</code> method:
</p>
<pre class="eval"><span class="highlightblue">// Get the RDF service</span>
var RDF =
  Components
  .classes["@mozilla.org/rdf/rdf-service;1"]
  .getService(Components.interfaces.nsIRDFService);
<span class="highlightblue">// ...and from it, get the datasource. Make sure that your web server
// dishes it up as <b>text/xml</b> (recommended) or <b>text/rdf</b>!</span>
var ds = RDF.GetDataSource("http://www.mozilla.org/some-rdf-file.rdf");
<span class="highlightblue">// Note that <b>ds</b> will load asynchronously, so assertions will not
// be immediately available</span>
</pre>
<p>Alternatively, you can create one directly using the XPCOM
Component Manager, as the following code fragment illustrates:
</p>
<pre class="eval"><span class="highlightblue">// Create an RDF/XML datasource using the XPCOM Component Manager</span>
var ds =
  Components
  .classes["@mozilla.org/rdf/datasource;1?name=xml-datasource"]
  .createInstance(Components.interfaces.nsIRDFDataSource);
<span class="highlightblue">// The <a class="external" href="http://lxr.mozilla.org/mozilla/source/rdf/base/idl/nsIRDFRemoteDataSource.idl">nsIRDFRemoteDataSource</a> interface has the interfaces
// that we need to setup the datasource.</span>
var remote =
   ds.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource);
<span class="highlightblue">// Be sure that your web server will deliver this as <b>text/xml</b> (recommended) or <b>text/rdf</b>!</span>
remote.Init("http://www.mozilla.org/some-rdf-file.rdf");
<span class="highlightblue">// Make it load! Note that this will happen asynchronously. By setting
// <b>aBlocking</b> to true, we could force it to be synchronous, but this
// is generally a bad idea, because your UI will completely lock up!</span>
remote.Refresh(false);
<span class="highlightblue">// Note that <b>ds</b> will load asynchronously, so assertions will not
// be immediately available</span>
</pre>
<p>You may decide that you need to "manually" create an RDF/XML
datasource if you want to force it to load synchronously.
</p>
<h3 name="How_do_I_reload_an_RDF.2FXML_datasource.3F">How do I reload an RDF/XML datasource?</h3>
<p>You can force an RDF/XML datasource (or any datasource that
supports <a class="external" href="http://lxr.mozilla.org/mozilla/source/source/rdf/base/idl/nsIRDFRemoteDataSource.idl"><code>nsIRDFRemoteDataSource</code></a>) using <code>Refresh()</code> method of
<code>nsIRDFRemoteDataSource</code>. <code>Refresh()</code> takes a
single parameter that indicates whether you'd like it to perform
its operation synchronously ("blocking") or asynchrounously
("non-blocking"). You should <em>never</em> do a synchronous load
unless you <em>really</em> know what you're doing: this will freeze
the UI until the load completes!
</p>
<h3 name="How_can_I_tell_if_an_RDF.2FXML_datasource_has_loaded.3F">How can I tell if an RDF/XML datasource has loaded?</h3>
<p>Using the <a class="external" href="http://lxr.mozilla.org/mozilla/source/source/rdf/base/idl/nsIRDFRemoteDataSource.idl"><code>nsIRDFRemoteDataSource</code></a> interface, it is possible to immediately query
the <code>loaded</code> property to determine if the datasource has
loaded or not:
</p>
<pre class="eval"><span class="highlightblue">// Get the RDF service</span>
var RDF =
  Components
  .classes["@mozilla.org/rdf/rdf-service;1"]
  .getService(Components.interfaces.nsIRDFService);
<span class="highlightblue">// Get the datasource.</span>
var ds = RDF.GetDataSource("http://www.mozilla.org/some-rdf-file.rdf");
<span class="highlightblue">// Now see if it's loaded or not...</span>
var remote =
  ds.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource);

if (remote.loaded) {
  alert("the datasource was already loaded!");
}
else {
  alert("the datasource wasn't loaded, but it's loading now!");
}
</pre>
<p>Say the datasource <em>wasn't</em> loaded, and is loading
asynchronously. Using this API and JavaScript's
<code>setTimeout()</code>, one could set up a <em>polling loop</em>
that would continually check the <code>loaded</code> property. This
is kludgy, and even worse, won't detect a <em>failed</em> load, for
example, because there wasn't any data at the URL!
</p><p>For this reason, there is an <a class="external" href="http://lxr.mozilla.org/mozilla/source/rdf/base/idl/nsIRDFXMLSink.idl">observer interface</a> that allows you to spy on a datasource's progress. The following
code illustrates its usage:
</p>
<pre class="eval"><span class="highlightblue">// This is the object that will observe the RDF/XML load's progress</span>
var Observer = {
  onBeginLoad: function(aSink)
    {},

  onInterrupt: function(aSink)
    {},

  onResume: function(aSink)
    {},

  onEndLoad: function(aSink)
    { alert("done!"); },

  onError: function(aSink, aStatus, aErrorMsg)
    { alert("error! " + aErrorMsg); }
};
<span class="highlightblue">// Get the RDF service</span>
var RDF =
  Components
  .classes["@mozilla.org/rdf/rdf-service;1"]
  .getService(Components.interfaces.nsIRDFService);
<span class="highlightblue">// Get the datasource.</span>
var ds = RDF.GetDataSource("http://www.mozilla.org/some-rdf-file.rdf");
<span class="highlightblue">// Now see if it's loaded or not...</span>
var remote =
  ds.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource);

if (remote.loaded) {
  alert("the datasource was already loaded!");
}
else {
  alert("the datasource wasn't loaded, but it's loading now!");
  <span class="highlightblue">// RDF/XML Datasources are all <b>nsIRDFXMLSink</b>s</span>
  var sink =
    ds.QueryInterface(Components.interfaces.nsIRDFXMLSink);
  <span class="highlightblue">// Attach the observer to the datasource-as-sink</span>
  sink.addXMLSinkObserver(Observer);
  <span class="highlightblue">// Now <b>Observer'</b>s methods will be called-back as
  // the load progresses.</span>
}
</pre>
<p>Note that the observer will remain attached to the RDF/XML
datasource unless <code>removeXMLSinkObserver</code> is called.
</p>
<h3 name="How_do_I_access_the_information_in_a_datasource.3F">How do I access the information in a datasource?</h3>
<p>The <a class="external" href="http://lxr.mozilla.org/mozilla/source/rdf/base/idl/nsIRDFDataSource.idl"><code>nsIRDFDataSource</code></a> interface is the means by which you access and manipulate the assertions in a datasource.
</p>
<ul>
<li>
<code>boolean HasAssertion(aSource, aProperty, aTarget, aTruthValue)</code>.<br>
This tests the datasource to see if it has the specified tuple.
</li>
<li>
<code>nsIRDFNode GetTarget(aSource, aProperty, aTruthValue)</code>.
</li>
<li>
<code>nsISimpleEnumerator GetTargets(aSource, aProperty, aTruthValue)</code>.
</li>
<li>
<code>nsIRDFResource GetSource(aProperty, aTarget, aTruthValue)</code>.
</li>
<li>
<code>nsISimpleEnumerator GetSoruces(aProperty, aTarget, aTruthValue)</code>.
</li>
<li>
<code>nsISimpleEnumerator ArcLabelsIn(aTarget)</code>.
</li>
<li>
<code>nsISimpleEnumerator ArcLabelsOut(aSource)</code>.
</li>
</ul>
<p>You can also use the <a href="#How_do_I_manipulate_RDF_.22containers.22.3F">RDF container</a> interfaces to access information contained in RDF <em>containers</em>.
</p>
<h3 name="How_do_I_change_information_in_the_datasource.3F">How do I change information in the datasource?</h3>
<h3 name="How_do_I_save_changes_to_an_RDF.2FXML_datasource_back.3F">How do I save changes to an RDF/XML datasource back?</h3>
<p>An RDF/XML datasource can be <code>QueryInterface()</code>'d to <a class="external" href="http://lxr.mozilla.org/mozilla/source/rdf/base/idl/nsIRDFRemoteDataSource.idl"><code>nsIRDFRemoteDataSource</code></a>. This interface has a <code>Flush()</code> method, which will attempt
to write the contents of the datasource back to the URL from which
they were loaded, using a protocol specific mechanism (e.g., a
<code>file:</code> URL just writes the file; an <code>http:</code> URL
might do an HTTP-POST). <code>Flush()</code> only writes the
datasource if its contents have changed.
</p>
<h3 name="How_do_I_merge_two_or_more_datasources_to_view_them_as_one.3F">How do I merge two or more datasources to view them as one?</h3>
<h3 name="How_do_I_access_.22built-in.22_datasources.3F">How do I access "built-in" datasources?</h3>
<p>A <em>built-in datasource</em> is a locally-installed component
that implements <a class="external" href="http://lxr.mozilla.org/mozilla/source/rdf/base/idl/nsIRDFDataSource.idl">nsIRDFDataSource</a>. For example, the <a class="external" href="http://lxr.mozilla.org/mozilla/source/xpfe/components/bookmarks/src/nsBookmarksService.cpp">bookmarks service</a>. First, check <a href="#What_is_the_security_model_for_RDF.2FXML_in_XUL.3F">here</a> to make
sure you will be <em>allowed</em> to access a built-in
datasource. There are several security restrictions on accessing
built-in datasources from "untrusted" XUL and JS.
</p><p>Since a built-in datasource is just an XPCOM component, you can
instantiate it directly using the XPConnect component manager.
</p>
<pre class="eval">// Use the component manager to get the bookmarks service
<span class="highlightgreen">var bookmarks =
  Components.
  classes["@mozilla.org/rdf/datasource;1?name=bookmarks"].
  getService(Components.interfaces.nsIRDFDataSource);</span>

// Now do something interesting with it...
if (bookmarks.HasAssertion(
     RDF.GetResource("http://home.netscape.com/NC-rdf#BookmarksRoot"),
     RDF.GetResource("http://home.netscape.com/NC-rdf#child"),
     RDF.GetResource("http://home.netscape.com/NC-rdf#PersonalToolbarFolder"),
     true) {
  // ...
}
</pre>
<p>Alternatively, some datasources have "special" RDF-friendly
ContractIDs that make it easy to instantiate the datasource using
either the <a class="external" href="http://lxr.mozilla.org/mozilla/source/rdf/base/idl/nsIRDFService.idl"><code>nsIRDFSerivce</code></a>'s <code>GetDataSource()</code> method or the <code>datasources</code>
attribute on a XUL template. These ContractIDs are of the form
</p>
<pre class="eval">@mozilla.org/rdf/datasource;1?name=<i>name</i>
</pre>
<p>And are accessable via <code>GetDataSource()</code> and the
<code>datasources</code> attribute using the shorthand
<code>rdf:<i>name</i></code>. For example, the following XUL
fragment illustrates how to add the bookmarks service as a
datasource into a XUL template.
</p>
<pre class="eval">&lt;tree datasources="rdf:bookmarks"&gt;
  ...
&lt;/tree&gt;
</pre>
<h3 name="How_do_I_manipulate_RDF_.22containers.22.3F">How do I manipulate RDF "containers"?</h3>
<p>To manipulate an RDF "container" (an <code>&lt;rdf:Seq&gt;</code>,
for example), you can use <a class="external" href="http://lxr.mozilla.org/mozilla/source/rdf/base/idl/nsIRDFContainerUtils.idl"><code>nsIRDFContainerUtils</code></a> which can be instantiated as a service with the following ContractID:
</p>
<pre class="eval">@mozilla.org/rdf/container-utils;1
</pre>
<p>You can use this service to detect if something is an RDF container
using <code>IsSeq()</code>, <code>IsBag()</code>, and
<code>IsAlt()</code>. You can "make a resource into a container" if it
isn't one already using <code>MakeSeq()</code>,
<code>MakeBag()</code>, or <code>MakeAlt()</code>. These methods
return an <a class="external" href="http://lxr.mozilla.org/mozilla/source/rdf/base/idl/nsIRDFContainer.idl"><code>nsIRDFContainer</code></a> which allows you to do container-like operations without getting your
hands too dirty.
</p><p>Alternatively, if your datasource already has an object that
<em>is</em> an RDF container, you can instantiate an
<code>nsIRDFContainer</code> object with the
</p>
<pre class="eval">@mozilla.org/rdf/container;1
</pre>
<p>ContractID and <code>Init()</code> it with the datasource and
resource as parameters. Note that this will fail if the resource
isn't already a container.
</p>
<h2 name="XUL_Templates">XUL Templates</h2>
<p>XUL templates are created by specifying a <code>datsources</code>
attribute on an element in a XUL document.
</p><p>There are two "forms" that XUL templates may be written in. The
"simple" form, which is currently the most common form in the
Mozilla codebase, and the "extended" form, which allows for
sophisticated pattern matching against the RDF graph. See the <a href="en/XUL/Template_Guide">XUL:Template Guide</a>. (These are bizarrely arranged because the <em>eventual</em> intent
is to introduce templates using the extended form -- which in many
ways is conceptually simpler, even if more verbose -- and then
treat the "simple" form as a shorthand for the extended form.)
</p>
<h3 name="What_can_I_build_with_a_XUL_template.3F">What can I build with a XUL template?</h3>
<p>You can build <em>any</em> kind of content using a XUL
template. You may use any kind of tag (including
HTML, or arbitrary XML) in the <code>&lt;action&gt;</code> section of
a <code>&lt;rule&gt;</code>.
</p>
<h3 name="When_should_I_use_a_XUL_template.3F">When should I use a XUL template?</h3>
<p>One alternative to using RDF and XUL templates is to use the <a class="external" href="http://www.w3.org/TR/REC-DOM-Level-1/">W3C DOM APIs</a> to build up and manipulate a XUL (or HTML) content model. There are
times, however, when doing so may be inconvenient:
</p>
<ol>
<li>
<em>There are several "views" of the data</em>. For example,
Mozilla mail/news reveals the folder hierarchy in the toolbar, the
"folder pane", in several menus, and in some of the
dialogs. Rather than writing three pieces of JS (or C++) code to
construct the DOM trees each
for <code>&lt;menubutton&gt;</code>, <code>&lt;menu&gt;</code>,
and <code>&lt;tree&gt;</code> content models, you write three
compact sets of rules for each content model.
</li>
<li>
<em>The data can change</em>. For example, a mail/news user may
add or remove IMAP folders. (Note how this requirement complicates
the task of building a content model!) The XUL template builder
uses the rules to automatically keep <em>all</em> content models
in sync with your changes.
</li>
</ol>
<p>In order to take advantage of this functionality, you must of
course be able to express your information in terms of the <a class="external" href="http://lxr.mozilla.org/mozilla/source/rdf/base/idl/nsIRDFDataSource.idl">RDF datasource API</a>, either by using the built-in <em>memory datasource</em>, using
RDF/XML to store your information, or writing your own
implementation (possibly in JavaScript)
of <code>nsIRDFDataSource</code>.
</p>
<h3 name="What_gets_loaded_when_I_specify_.22datasources.3D.22">What gets loaded when I specify "datasources="</h3>
<p>The <code>datasources</code> attribute on the "root" of a template
specifies a whitespace-separated list of <em>datasource URIs</em>
to load. But what is a "datasource URI"? It is either:
</p>
<ul>
<li>
An abbreviated ContractID for a locally installed component. By specifying
<code>rdf:<i>name</i></code>, you instruct the template builder to
load the XPCOM component with the ContractID <code>@mozilla.org/rdf/datasource;1?name=<i>name</i></code>.
</li>
<li>
The URL of an RDF/XML file. For example,
<pre>file:///tmp/foo.rdf
chrome://mycomponent/content/component-data.rdf
http://www.mysite.com/generate-rdf.cgi
ftp://ftp.somewhere.org/toc.rdf
</pre>
<p>The load will be processed <em>asynchronously</em>, and as
RDF/XML arrives, the template builder will generate content.
</p>
</li>
</ul>
<p>In either case, the datasource will be loaded using the <a class="external" href="http://lxr.mozilla.org/mozilla/source/rdf/base/idl/nsIRDFService.idl"><code>nsIRDFService</code></a>'s <code>GetDataSource()</code> method, so it will be <a href="#How_does_Mozilla_manage_datasources.3F">managed</a> similarly to all other datasources loaded this way.
</p>
<h3 name="What_is_the_security_model_for_RDF.2FXML_in_XUL.3F">What is the security model for RDF/XML in XUL?</h3>
<p>XUL that is loaded from a "trusted" URL (currently, any
<code>chrome:</code> URL) can specify <em>any</em> datasource URI
in the <code>datasources</code> attribute of the XUL template.
</p><p>XUL that is loaded from an "untrusted" URL can only specify an RDF/XML
document from the same <em>codebase</em> (in the Java sense of the
word) that the XUL document originated from. No "special" (i.e.,
<code>rdf:</code>) datasources may be loaded from untrusted XUL.
</p>
<h3 name="How_do_I_add_a_datasource_to_a_XUL_template.3F">How do I add a datasource to a XUL template?</h3>
<p>Although it's possible to create a XUL template with an "implicit" set
of datasources by specifying the <code>datasources</code> attribute,
there are often times when you won't know the datasource that you want
to add until <em>after</em> the XUL is loaded. For example, your XUL
may need compute the datasources that it wants to display in an
<code>onload</code> handler. Or, it may need to add a datasource
later based on some user action.
</p><p>Here's a simple example that illustrates how to do this. Let's
start with the following XUL.
</p>
<pre class="eval">&lt;window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"&gt;
  ...
  <span class="highlightgreen">&lt;tree id="my-tree" datasources="rdf:null"&gt;
    ...
  &lt;/tree&gt;</span>
  ...
&lt;/window&gt;
</pre>
<p>Assuming that we've aquired a datasource somehow (e.g., like <a href="#How_do_I_create_a_datasource_from_an_RDF.2FXML_file.3F">this</a>), the following sample code illustrates how to <em>add</em> that
datasource to the template, and then force the template to rebuild
itself based on the newly added datasource's contents.
</p>
<pre class="eval">var ds = <span class="highlightblue">/* assume we got this somehow! */</span>;
<span class="highlightblue">// Get the DOM element for 'my-tree'</span>
var tree = document.getElementById('my-tree');
<span class="highlightblue">// Add our datasource to it</span>
tree.database.AddDataSource(ds);
<span class="highlightblue">// Force the tree to rebuild *now*. You have to do this "manually"!</span>
tree.builder.rebuild();
</pre>
<p>Any XUL element with a <code>datasources</code> attribute will "get" a
<code>database</code> property and a <code>builder</code> property.
The <code>database</code> property refers to an <a class="external" href="http://lxr.mozilla.org/mozilla/source/rdf/base/idl/nsIRDFCompositeDataSource.idl"><code>nsIRDFCompositeDataSource</code></a> object, which is contains the datasources from which the template is
built.
</p><p>The <code>builder</code> property refers to an <a class="external" href="http://lxr.mozilla.org/mozilla/source/rdf/base/idl/nsIXULTemplateBuilder.idl"><code>nsIXULTemplateBuilder</code></a> object, which is a the "builder" that maintains the state of the
template's contents.
</p><p>Note the <code>rdf:null</code> datasource: this is a special
datasource that says, "hey, I don't have a datasource for you yet, but
I'm going to add one later, so set yourself up for it!" It causes the
<code>database</code> and <code>builder</code> properties to get
installed, but leaves the <code>database</code> empty of
datasources: you've got to add these in yourself!
</p>
<h3 name="Can_I_manipulate_a_XUL_template_using_the_DOM_APIs.3F">Can I manipulate a XUL template using the DOM APIs?</h3>
<p>Yes: you can add rules, remove rules, change a rule's conditions, and
change the content that is built by a rule. In fact, you can change
<em>anything</em> about a template using the <a class="external" href="http://www.w3.org/TR/REC-DOM-Level-1/">W3C DOM APIs</a>.
</p><p>The only caveat is that you must call <code>rebuild()</code> before
the changes you've made will take effect (just as you must if you <a href="#How_do_I_add_a_datasource_to_a_XUL_template.3F">add a datasource</a> to the XUL
template).
</p>
<h3 name="How_do_I_insert_plaintext_from_a_template.3F">How do I insert plaintext from a template?</h3>
<p>To insert plaintext in a template, use the <code>&lt;text&gt;</code>
element.
</p>
<pre class="eval">&lt;template&gt;
  &lt;rule&gt;
    &lt;conditions&gt;...&lt;/condition&gt;
    &lt;bindings&gt;...&lt;/bindings&gt;
    &lt;action&gt;
      <span class="highlightgreen">&lt;text value="?some-variable" /&gt;</span>
    &lt;/action&gt;
  &lt;/rule&gt;
&lt;/template&gt;
</pre>
<p>The above template will create a content model that runs a series
of text nodes together.
</p>
<h2 name="Troubleshooting">Troubleshooting</h2>
<p>Tricks and tips from the field.
</p>
<h3 name="My_RDF.2FXML_file_won.27t_load.">My RDF/XML file won't load.</h3>
<p>The most common cause for RDF/XML not to load from a web server is
incorrect MIME type. Make sure your server is delivering the file as
<code>text/xml</code> (recommended) or <code>text/rdf</code>
(bogus).
</p><p>Note that the W3C RDF Core WG are registering application/rdf+xml,
though this isn't understood by any Mozilla code yet. (do we have a
bug registered to track this? -- <a class="external" href="mailto:danbri-mozilla@rdfweb.org">danbri</a>)
</p><p>Another possible problem: for remotely-loaded XUL and RDF, you
might need to adjust Mozilla's security restrictions (see belowfor
example code). If XUL isn't loading your RDF, and the mimetype is
OK, this could well be your problem.
</p><p>You can use the <code>rdfcat</code> and <code>rdfpoll</code> utilities
to verify that the RDF/XML is actually valid. Both of these programs
are built by default on Windows, and on Linux when the
<code>configure --enable-tests</code> is specified.
</p>
<ul>
<li>
<code><a class="external" href="http://lxr.mozilla.org/mozilla/source/rdf/tests/rdfcat/rdfcat.cpp">rdfcat</a> <i>url</i></code><br>
Takes as a parameter a URL from which to read an RDF/XML file,
and will "cat" the file back to the console. You can use it to
verify that the RDF/XML that you've written is being properly
parsed by Mozilla.
</li>
<li>
<code><a class="external" href="http://lxr.mozilla.org/mozilla/source/rdf/tests/rdfpoll/rdfpoll.cpp">rdfpoll</a> <i>url</i> {{mediawiki.external('&lt;i&gt;interval&lt;/i&gt;')}}</code><br>
Takes as a parameter a URL from which to read an RDF/XML file. It also accepts an optional <em>poll interval</em>, where it will
re-load the URL. It outputs the assertions that are generated
from each load. Note that a polling reload generates a set
of <em>differences</em> between the current and previous contents
of the RDF/XML file. This is useful for debugging generated
RDF/XML that may change over time.
</li>
</ul>
<p>Both these programs are slow to load and run (but
they <em>will</em> run, eventually). They initialize XPCOM and
bring up Necko to be able to load and process URLs just like
Mozilla does.
</p>
<h3 name="Nothing_happens_after_I_call_AddDataSource.">Nothing happens after I call AddDataSource.</h3>
<p>Note that the template builder will <em>not</em> rebuild the
contents of a template automatically
after <code>AddDataSource</code> or <code>RemoveDataSource</code>
have been called on the builder's <code>database</code>.  To
refresh the template's contents, you must manually
call <code><i>elt.</i>builder.rebuild()</code> yourself.
</p><p>Why?  This was done to avoid multiple rebuilds when more than one
datasource is added to the <code>database</code>.
</p>
<h2 name="Examples">Examples</h2>
<h3 name="Where_can_I_find_some_.28working.29_examples.3F">Where can I find some (working) examples?</h3>
<p>A few examples are posted <a class="external" href="http://www.mozilla.org/rdf/doc/examples.html">here</a>. Some of these are included in signed scripts, and are runnable from
HTTP directly.
</p><p>See also <a class="external" href="https://bugzilla.mozilla.org/data/duplicates.rdf"><code>duplicates.rdf</code></a> (for live RDF feed from Mozilla) alongside <a class="external" href="https://bugzilla.mozilla.org/duplicates.xul"><code>duplicates.xul</code></a>. Note that for these to work, you have to relax Mozilla's <a href="en/Bypassing_Security_Restrictions_and_Signing_Code">security model</a>. To do this, add the following line to your preferences file. (Shut
down Mozilla first since it overwrites your preferences file when
you quit.)
</p>
<pre class="eval">user_pref("signed.applets.codebase_principal_support", true);
</pre>
<p>Mozilla will ask you if you want to grant the scripts in
<code>duplicates.xul</code> permission to access XPConnect; respond
in the affirmative.
</p><p>Currently, Mozilla does not allow unprivileged access to the RDF
interfaces and services; see bug <a class="external" href="https://bugzilla.mozilla.org/show_bug.cgi?id=122846">122846</a> for details.
</p><p>Please mail <a class="external" href="http://rdfweb.org/people/danbri/">danbri</a>, mozilla-rdf or waterson with URLs if you are aware of other
examples to which we ought to link!
</p>
<h2 name="Notes">Notes</h2>
<ol><li> See also <a class="external" href="http://www.w3.org/RDF/">W3C RDF</a> and <a class="external" href="http://www.w3.org/2001/sw/">Semantic Web</a> pages for more information on RDF and related technologies.
</li></ol>
<h2 name="Contributors">Contributors</h2>
<ul><li> Examples section added 2002-07-02 by <a class="external" href="http://rdfweb.org/people/danbri/">danbri</a> &lt;/li&gt;
</li><li> Thanks to Myk Melez for notes on remote XUL / security policy
</li></ul>
<p>Author: <a class="external" href="mailto:waterson@netscape.com">Chris Waterson</a>
</p>
<div class="originaldocinfo">
<h2 name="Original_Document_Information">Original Document Information</h2>
<ul><li> Author(s): <a class="external" href="mailto:waterson@netscape.com">Chris Waterson</a>
</li><li> Last Updated Date: December 22, 2004
</li><li> Copyright Information: Copyright (C) <a class="external" href="mailto:waterson@netscape.com">Chris Waterson</a>
</li></ul>
</div>
Revert to this revision