XUL templates are apparently difficult for many to understand. Unfortunately there are a lot of bits to have to learn to be able to use them effectively: RDF, the querying syntax, and some additional XUL features. The lack of useful logging and error messages makes things doubly difficult. Perhaps templates may be a bit easier on someone if they had an understanding of how tenplates actually work. This is part one in what will hopefully be a longer series of posts about this topic.
To begin, a XUL template is a means of producing a block of content for each result from some query or query-like operation. A good analogy is to the results of a database query. For each result returned from the query, generate some content. The template syntax allows for different rules to generate different content based on particular criteria as well as set attribute values from returned results. Some other systems call this databinding. Effectively, XUL templates are the XUL way of doing databinding. However, with a template, there are two restrictions. First, you can only generate content from the results of a query. You can't just take a single piece of data and assign it to an attribute, since templates are designed for repeated blocks of data. Second, you can only bind to an RDF datasource. These restrictions should be removed in the future.
In XUL, the RDF datasource is specified by placing the 'datasources' attribute on an element. When the XUL parser sees an element with this attribute, it constructs a template builder for the element and attaches it to the element. It is expected that there will be a template inside the element. The template builder loads the datasource, performs the query on the datasource and generates content for each result. The content is inserted into the XUL just as if you had placed it there yourself. Here is an example:
This example specifies the datasource 'http://www.xulplanet.com/ds/sample.rdf'.
The template builder loads the datasource using the RDF service in the same way as you would create a datasource through the RDF service directly. The datasource is loaded via its URL. Some RDF datasources are provided with Mozilla -- their URL's start with 'rdf:'. Otherwise, the datasource is loaded as any other URL is loaded. If the datasource is already loaded and cached, the template builder can begin work right away. Otherwise, there isn't anything to do until the data is loaded. Actually, this isn't quite true. The RDF service starts the load of the datasource in the background and the template builder goes through the process of building content anyway. Naturally, since there is no data yet, no results will be available so the builder ends up building nothing.
Once some data starts arriving, the template builder scans its information to see if some results can be created. If so, some content can be generated. If not, nothing gets generated again. An interesting thing to note is that due to the nature of the RDF parsing process, the builder generates results and builds content incrementally while the data arrives. Of course, since the data arrives so quickly from the network, you really don't notice this. If the datasource is already loaded, the builder can construct content all in one step, although even this isn't completely true as we'll see later.
The template builder can also use multiple datasources which are all combined into a single datasource as if they were all in one datasource to begin with. An nsIRDFCompositeDataSource is used for this purpose. You can get this composite datasource in a script by using an element's 'database' property if you want to add or remove datasources from it.
As mentioned, the template builder loads the datasources by passing the URLs to the RDF service. However, the special URL rdf:null is used to indicate that you mean no datasources, or an empty datasource. The composite datasource will still be created but no datasources will be added to it. This is used when you need to specify the datasource dynamically with a script.
In addition, for chrome XUL (such as extensions), the datasource rdf:local-store is always included in the composite. The local store is a datasource which is usually used to hold state information such as window sizes, which columns in a tree are showing and which tree items are open. You can query for any data in the local store in a template although this is rarely done.
When multiple datasources are used the RDF is combined as if it was one large datasource. That means that a template query can grab data from anywhere in all of the datasources. This combining of datasources is often termed aggregation. This can be quite a useful feature and works regardless of the datasource. For instance, you might use the built-in bookmarks datasource which holds the user's browser bookmarks and use your own datasource to add custom data about those bookmarks.
<vbox datasources="rdf:bookmarks http://www.xulplanet.com/ds/sample.rdf">
In part two, we'll look at the ref attribute.