So far, every template has contained only a single query, even for recursive content. However, it is possible to use multiple queries. This may be used to combine the results from several queries together, or may be used to generate different types of results when recursive iterations. To use multiple queries, place each
query element along with its rules inside a
queryset element. The
queryset element is a bit of a misnomer, it actually only contains one query each.
The following is the basic structure of a template with multiple queries:
<listbox datasources="..." ref="..."> <queryset> <query> ... </query> <rule> ... </rule> </queryset> <queryset> <query> ... </query> <rule> ... </rule> </queryset> </listbox>
queryset holds a query and its set of rules. If there is only rule, the
rule element may be omitted as is the case when only one query is used. The results from the first query are generated first and output generated for it, followed by the results and output for the second query, and so forth for all of the queries. Here is an example using an RDF datasource:
<hbox id="photosList" datasources="template-guide-photos3.rdf" ref="http://www.xulplanet.com/rdf/myphotos"> <template> <queryset> <query> <content uri="?start"/> <member container="?start" child="?photo"/> <triple subject="?photo" predicate="http://purl.org/dc/elements/1.1/title" object="Canal"/> </query> <action> <button uri="?photo" image="?photo" label="View" orient="vertical"/> </action> </queryset> <queryset> <query> <content uri="?start"/> <member container="?start" child="?photo"/> </query> <action> <image uri="?photo" src="?photo"/> </action> </queryset> </template> </hbox>
This template contains two queries, the first contains a <triple> which matches only the photo with a title of 'Canal'. The second query doesn't contain such a triple and will match all three of the photos. It the first query was used by itself, only one result would match. If the second query was used by itself, three results would match. When used together in this example, the results are combined and only three results are shown. However, you will probably notice that the one photo that matches the first query has appeared differently that the others. In fact, the content for this photo is that of the first query with the button, whereas the content for the other photos are that of the second query with the normal images.
This method of using multiple queries allows different content to generated for each query. In this particular example, we could actually have used two rules instead. This would be a better idea as it only requires one query, is simpler and more efficient, however you could imagine a more complex query where this wasn't possible.
How Multiple Queries are Processed
We already know that a query generates a set of results. There's no magic to the way in which the template builder processes multiple queries. It just takes the results generated from the first query, adds the results for the second query, adds the results for the third query, and so on. Here are the results that would be generated by the first query above, before any bindings are applied:
(?start = http://www.xulplanet.com/rdf/myphotos, ?photo = http://www.xulplanet.com/ndeakin/images/t/canal.jpg,
Then, the builder adds the three results generated from the second query:
(?start = http://www.xulplanet.com/rdf/myphotos, ?photo = http://www.xulplanet.com/ndeakin/images/t/canal.jpg) (?start = http://www.xulplanet.com/rdf/myphotos, ?photo = http://www.xulplanet.com/ndeakin/images/t/palace.jpg) (?start = http://www.xulplanet.com/rdf/myphotos, ?photo = http://www.xulplanet.com/ndeakin/images/t/canal.jpg) (?start = http://www.xulplanet.com/rdf/myphotos, ?photo = http://www.xulplanet.com/ndeakin/images/t/obelisk.jpg)
So four possible results are available, one from the first query and three from the second. However, the example shows that only content for three results are generated. What happened to the fourth result?
This is where the useful aspect of multiple queries comes in. Note that two of the results above are actually for the same photo (canal.jpg). The template builder removes any duplicate items before generating content. It does this by only allowing the match for the earliest query. That is, the canal.jpg generated by the second query is removed, since an earlier query (the first query) already generated a match for that result.
One important distinction is that the determination of duplicates is only based on the member variable, in this case the ?photo variable. It doesn't matter whether other variables are the same or not.
If you look at the example again, you might notice that the canal photo that matches the first query has appeared in-between the other two photos, even though those photos are generated from the second query. The builder hasn't put all the matches for the first query before the matches for the second query. In fact, the order is the same as the examples that only use one query. Compare the multiple query example with an earlier example that used only a single query. The photos have appeared in the same order in both cases.
This is because the builder notices that the photos are in an RDF Seq in the datasource and arranges them in the order they appear in the Seq. This and other automated sorting done by the template builder is a fairly complicated process that will be discussed in more detail later.
Multiple Queries Using the RDF Simple Syntax
You can also use multiple queries with RDF datasources using the simple query syntax. Here is the previous example rewritten using the simple syntax:
<hbox id="photosList" datasources="template-guide-photos3.rdf" ref="http://www.xulplanet.com/rdf/myphotos" xmlns:dc="http://purl.org/dc/elements/1.1/"> <template> <rule dc:title="Canal"> <button uri="rdf:*" image="rdf:*" label="View" orient="vertical"/> </rule> <rule> <image uri="rdf:*" src="rdf:*"/> </rule> </template> </hbox>
The result to the user in this example is the same as the previous example. You can also mix simple and extended queries in one template, although you may prefer to use the same style in all queries for consistency.
However, if you are going to be using a number of queries, the template builder is more efficient when using multiple queries using the simple query syntax. This is because all simple queries will iterate over the same data, usually the children of an RDF container. So the builder only performs this step once and filters the data for each query.
When using the extended query syntax, the manner in which the graph is navigated may be different for every query, so no optimization can be done. The builder needs to process every condition of every query. If, for example, you have six queries, each with a <member> condition, the builder will need to construct the children six times. You probably won't notice any difference for small amounts of data such as the photos example we've been using, but you might for large datasets. Thus, you will want to use the simple query syntax when possible.
If you are only going to be using one query, it doesn't matter, of course. Speaking of using a single query, the simple query syntax allows a slight shorthand. You can remove the <rule> element and place the rule's conditions directly on the <template>. There's no performance benefit, but it does save some typing.
<hbox id="photosList" datasources="template-guide-photos3.rdf" ref="http://www.xulplanet.com/rdf/myphotos" xmlns:dc="http://purl.org/dc/elements/1.1/"> <template dc:title="Canal"> <button uri="rdf:*" image="rdf:*" label="View" orient="vertical"/> </template> </hbox>
This example shows only a single photo since a condition is used to filter out the other two photos. Note that in this shorthand, the query conditions are placed directly on the <template> element.