XUL templates are dynamically generated XUL elements and groups of XUL elements. They are often used to render lists and tables that display mutable, frequently updated data, such as your Inbox, your list of bookmarks, and user profiles. A XUL template can be used to create something as simple as a list of menu items, as you will see here, but it can also be used in much more exciting ways, as shown at the end of this chapter. You should consider using a XUL template instead of XUL when you want to create an interface that displays data, such as a roster of names, when the set of data is very large, when the data may change frequently, or when you create a display that you want to use for different sets of data.
RDF, the format for data that goes into templates, is described in detail in Chapter 10. The actual data used to build the template examples is displayed in Examples 10-1 and 10-4. However, this chapter precedes the RDF chapter because templates are much easier to understand than RDF. Extending on the XUL programming done in Chapters 2 and 3, templates are a practical application of RDF data. They can also help you understand the abstract concepts introduced in Chapter 10.
By defining special rules and applying them
to data stored in RDF files, XUL templates build user interfaces
dynamically. A XUL template consists of a set of special tags inside a
XUL element-often <listbox>
, <menu>
, or <tree>
elements that match data in an RDF datasource. A XUL template is defined
in a regular XUL file and may appear anywhere regular XUL content can
be placed.
The template defines rules for filling out the parent elements with
the associated RDF data. Example 9-1 shows how to
get a <listbox>
in XUL to display RDF file contents. A
template like this could display data stored in a RDF file that,
because it's so long, complex, or ephemeral, shouldn't be hardcoded
into XUL list elements. The data that comes from RDF and goes into a
template should be anything that doesn't directly relate to the user
interface.
Example 9-1: Simple XUL template in a listbox element
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?> <window
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <listbox datasources="10-1.rdf" ref="urn:root" flex="1">
<template>
<rule> <conditions>
<content uri="?jar"/>
<triple subject="?jar" predicate="http://xfly.mozdev.org/fly-rdf#types"
object="?types"/> <member container="?types" child="?type"/>
<triple subject="?type" predicate="http://xfly.mozdev.org/fly-rdf#name"
object="?name"/> </conditions>
<action>
<listitem uri="?type"> <listcell label="?name"/>
</listitem>
</action> </rule>
</template>
</listbox>
</window>
Because the template is built to match the RDF data, different parts of the template in Example 9-1 correspond to parts of the RDF file used as the datasource. Obviously, you need to know about the data's organization-the "graph" created by the data-to build effective templates for it. However, once you create the rules, you can apply them to very large sets of data, which is one of the benefits of using templates in the interface.
As you can see in Example 9-1, rules typically comprise most of a template's definition. The next several sections break down Example 9-1 to help you understand the parts of a XUL template.
Example 9-2 shows the template's
basic structure. In this case, the data that meets the conditions
defined in the conditions
element is rendered by the XUL
elements defined in the actions
element, allowing the
translation of RDF data into XUL elements.
Example 9-2: Basic structure of a XUL template
<listbox datasources="10-1.rdf" ref="urn:root">
<template>
<rule> <conditions>
...
</conditions>
<action>
... </action>
</rule>
</template>
</listbox>
In the first lines of the XUL template, a
<template>
is defined within a <listbox>
element, which is a simple container for templates in XUL:
XUL:
<listbox datasources="10-1.rdf" ref="urn:root" flex="1">
RDF:
<rdf:Description about="urn:root">
When it appears inside the <template>
, the <listbox>
tag has two special attributes. The datasources
attribute
specifies the RDF file's location. The ref
attribute is the
starting point in that RDF-based data for the template processing,
which is equivalent to the about
attribute of the root node in
the actual RDF file. The ref
attribute tells the template
where to begin reading the data in the RDF file, and the about
attribute in the RDF data file specifies where its own beginning is. In
this case, the RDF and XUL starting point is the root of the data. Note
that you do not need to define a template at the base of an RDF data
file: an RDF file may have several avenues of information (e.g.,
different groups of bookmarks) and your template may render only one
group or some portion of all of the RDF file data.
XUL:
<template>
<rule>
<conditions>
RDF:
<!-- no equivalent -->
The <template>
and <rule>
tags set up
the template. The template's rule element defines conditions that must
be met for the template to render the referenced data. A common
condition in a template, for example, is that an element be of a
particular type or have an attribute set to a certain value. The
conditions in Example 9-2 render this content (10-1.rdf)
if it defines a types
property and gives individual child
elements as types.
Applying template rules to a datasource drives the dynamic creation of the template-based UI. You can imagine a template going through data and selecting only the bits of data that match, based on matching rules, and then rendering that selected data into XUL (again based on rules defined in the template itself).
Generated values from the RDF are stored in variables that can be
used throughout the template. They are represented by the values inside
the attributes beginning with a ?
. When you create variables
in a template
once, you can use them wherever you need them in the template. In Example 9-1, the ?type variable is created as
a child of types
in the conditions block, is used again, and
is then used a third time in the action block to describe the element
that should be rendered in the template:
XUL:
<content uri="?jar"/>
<triple subject="?jar" predicate="http://xfly.mozdev.org/fly-rdf#types"
object="?types"/>
RDF:
... about="urn:root" ... ... xmlns:fly="http://xfly.mozdev.org/fly-rdf#" ...
</fly:types>
The <content>
tag signifies the root of the template
rule. The uri
attribute value is automatically filled with urn:root
from the listbox ref
attribute, which originates from the RDF about
attribute on the first resource. This value is now stored in the ?jar
variable. Assigning variables in a template for use elsewhere in the
template is an essential part of template-building in XUL, as it is in
programming languages that work with data.
A <triple>
is a test
on a subject and predicate. When triples match the subject and
predicate in the RDF, their object value is produced. In this case, the
container is the object result ?types
, which holds individual ?type
nodes. Each one of these is drawn as a <listitem>
.
The <member>
element
initiates a loop-like effect. When the template builds, this effect
exposes the container so it can read through all the objects and add
them to the template. In essence, ?type
holds three different
values throughout the template generation: [*]
XUL:
<member container="?types" child="?type"/>
RDF:
<fly:types>
<rdf:Bag>
<rdf:li>
<rdf:Description ...
To finish the template conditions, one more <triple>
correlates with the literal's value.
XUL:
<triple subject="?type"
predicate="http://xfly.mozdev.org/fly-rdf#name"
object="?name"/> RDF:
... xmlns:fly="http://xfly.mozdev.org/fly-rdf#" ...
<rdf:li> <rdf:Description fly:name="Horse"/>
Like ?type
, ?name
holds three different values
during its lifetime, and "Horse" will be the first value generated from
the RDF.
The <conditions>
part of the template extracts the data from the RDF graph, as in our
graphical examples. It makes the data available in variable-like
objects; those objects can be used in the template's <action>
,
demonstrated in the next section.
XUL elements
that are used to build content from data matched by the template
conditions are placed in the <action>
element in a
template rule. The <listbox>
is the most popular way to
display this data because all of its child elements fall neatly into
place inside the template. However, you can use any XUL element that
supports the type of tabular display required by the data (e.g., <tree>
,<groupbox>
,
and <menu>
).
<action>
<listitem uri="?type">
<listcell label="?name"/>
</listitem>
</action>
For the RDF content to be displayed, it needs a parent/children team
to define and fill in the values where needed. The parent, ?type
,
is used as a point of reference three times during its lifetime by
objects directly in the container. The template generates ?name
into the three literal children, as shown in Table 9-1.
Iteration | First child | Second child | Third child |
---|---|---|---|
?type | rdf:#$LtOki1 | rdf:#$MtOki1 | rdf:#$NtOki1 |
?name | "horse" | "house" | "fruit" |
Directly inside the <action>
element is the first XUL element that gets repeated, the <listitem>
.
This element must have the uri
attribute with the container's
object variable, which in Example 9-2 is ?type.
This variable establishes the root of the content-a point of reference
in the template for any children below that point.
Once the container elements are matched to the <listitem>
,?name
can be used in any attribute on any tag below it. In the previous
example code, the <listcell> label
shows the value of ?name
.
Interesting implementations can result from the use of variables to
hold values for attributes like class
, which is often used to
define style rules for elements. This implementation
is demonstrated in the section "Using Data for Style,"
later in this chapter
Example 9-3 shows what a generated template looks like as hardcoded XUL.
Example 9-3: Hardcoded representation of generated XUL
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?> <window
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<listbox datasources="10-1.rdf" ref="urn:root" flex="1">
<listitem id="rdf:#$mPgLw2">
<listcell label="Horse"/>
</listitem>
<listitem id="rdf:#$nPgLw2">
<listcell label="House"/>
</listitem>
<listitem id="rdf:#$oPgLw2">
<listcell label="Fruit"/>
</listitem>
</listbox>
</window>
It's beneficial to see how this document is translated into a DOM tree using Mozilla's DOM Inspector tool, with which the structure is presented in a view that makes it easy to follow. Figure 9-1 shows how the template tree nodes are generated into an actual tree. To use this tool, select "DOM Inspector" from the Tools > Web Development menu in Mozilla. If you have the template displayed in an open browser window, you can load it in the DOM Inspector by selecting File > Inspect a Window and choosing it from the list.
In Figure 9-1, you can see how the <listitem>
was generated three times from the template. Interestingly, the
generated code doesn't replace the original template, but is appended
to the <tree>
as another tree row.
Finally, Figure 9-2 shows what the actual XUL file looks like when loaded. If you save the template in Example 9-1 to a file called 9-1.xul, save the RDF data in Example 10-1 to a file called 10-1.rdf (which the template looks for by name in the same directory), and then load the template into the browser, you ought to see something very similar.
Creating simple XUL templates can help familiarize you with the
flexibility and complex design issues of a template. The RDF file
created in Example 9-4 introduces the concept of
nested content. A <listbox>
can generate nested content
from multiple containers in the RDF datasource. These multiple
containers must have the same basic design to work properly, so the
design must be abstracted to apply to all datasources. Example
9-5 uses the <fly:list>
design to accomplish this
task.
The advantage of having nested content in XUL templates is that you can organize items visually, even when those things come from different sources. Nested content allows you to form subtrees and submenus rather than long monolithic lists.
The window in Figure 9-3 represents
a template with nested data and styled elements. Note that the top of
the content area has a standard <listbox>
and a
color-styled <tree>
is on the bottom. The next several
sections describe the creation of the XUL file in Figure
9-3.
In this example, both the
<tree>
and the
<listbox>
use the same data, but different template formats.
Only two columns appear in the <listbox>
, for example,
and the rows were created to display the color of the data's color
attribute. You could as easily have styled the <tree>
this way and left the <listbox>
as a regular list. To
display large amounts of raw data, however, <tree>
is
usually the best option because it's faster with big datasets, offers
built-in sorting, and looks cleaner.
The <listbox>
template can make the XUL seem more
complicated than the content would seem to require in Figure
9-3, but a template's basic design can be similar for all types of
data, which allows you to write once and apply templates to different
datasets. In this case, you gain more efficiency because the RDF
contributes more to the template generation than does the XUL, making
template-based applications data-driven.
Example 9-4 contains the XUL for producing the tree shown in Figure 9-3. The difference between the code in Examples 9-2 and 9-9 is minimal, but the latter produces a much more impressive visual result. Remember that a XUL template and RDF produce the content you see when loading these listbox examples. No stylesheets or other enhancements are needed.
Example 9-4: XUL tree template in Figure 9-3
<listbox datasources="10-4.rdf" ref="urn:root" flex="1" containment="http://xfly.mozdev.org/fly-rdf#list">
<template>
<rule> <conditions>
<content uri="?uri"/>
<triple subject="?uri" predicate="http://xfly.mozdev.org/fly-rdf#list" object="?list"/> <member container="?list" child="?listitem"/>
<triple subject="?listitem" predicate="http://xfly.mozdev.org/fly-rdf#label" object="?label"/> </conditions>
<bindings>
<binding subject="?listitem" predicate="http://xfly.mozdev.org/fly-rdf#color" object="?color"/> <binding subject="?listitem"
predicate="fly-location#location" object="?location"/>
</bindings>
<action> <listitem uri="?listitem" class="?color"> <listcell label="?label" class="treecell-indent"/> <listcell label="?location" class="treecell-indent"/> </listitem>
</action>
</rule> </template>
<listcols>
<listcol flex="1"/> <listcol flex="1"/>
</listcols>
</listbox>
The biggest difference between Example 9-4 and
earlier examples is the <bindings>
section. All matching
in a binding element is optional, unlike the condition content. The
elements in the bindings are simply optional triples. Placing these
triples in a binding affords you some flexibility when data is missing
from the RDF file or when you are not certain about its contents-such
as when you create a roster but don't have all the people's addresses.
The containment
attribute on the tree specifies the URI of
all the containers. In this case, the container is the <fly:list>
tag in the RDF. To see how such a complex-looking <listbox>
can be generated from so little XUL, look at how the containers are set
up in the RDF. The RDF file appears (in a reformatted and somewhat
simplified form) in Example 9-5. This simplified
form can help you see the structure underlying the data and how it is
reused to order the data efficiently.
Example 9-5: Simplified version of 10-4 RDF data
<rdf:Description about="urn:root">
<fly:list>
<rdf:Seq> <rdf:li>
<rdf:Description ID="House"> <fly:label>House</fly:label>
<fly:list> <rdf:Seq>
<rdf:li> <rdf:Description about="musca_autumnalis" fly:label="Face Fly"/>
</rdf:li> <rdf:Seq>
</fly:list>
</rdf:li> </rdf:Seq>
</fly:list>
</rdf:Description>
The RDF data in Example 9-5 demonstrates a
two-level pattern of recursion: fly:list/fly:label
are both
reused at different levels in the RDF data. The template in Example 9-4 generates the data into a tree showing
two levels, as shown in Figure 9-3.
Example 9-5 clearly shows that only fly:list
and fly:label
are needed to generate the template. The other
data, such as color, are not mandatory because they are defined in a <binding>
rather than a <triple>
.
RDF data are used for more than
containers and labels. It's possible to use RDF to define CSS classes,
XUL attributes, and other arbitrary bits of XUL content. In Example 9-4, the <listitem>
has a class
attribute that is filled by ?color
:
<listitem uri="?listitem" class="?color">
<treecell label="?label"/>
<treecell label="?location"/>
</listitem>
If a stylesheet has class definitions for the same values located in the RDF, then every generated row can have its own style. Here is a simple class showing style rules defined for items of the "green" class.
.green
{
background-color: green;
}
As shown in the earlier examples of this chapter, using <listbox>
with templates generally yields flexible and simpler implementations.
Trees, covered next, are not as flexible, but they can be better for
raw data display, as when you have spreadsheet-like information, many
columns, or other data that can be sorted.
<tree>
is the best choice for
displaying simple data with better visual speed, automatic sorting, and
column selection capabilities. In contrast to listboxes, trees do not
create a full DOM representation data when the template generates.
Instead, a tree keeps data in its own database and updates its display
more quickly than a listbox when the user scrolls or sorts.
The XUL tree in Example 9-6 can be compared to
the listbox
XUL in Example 9-4. The
template design is almost exactly the same in both examples, but the
elements surrounding the template in the tree-treebody
, treecol
,
and treecells-
are more complex and allow a precise layout by
giving you more granular control over the parts of the layout. These
parts include the header, the columns, and the parent-child
relationships. XUL's parent element affects the presentation of the
template-based data.
Example 9-6: Tree template code of Figure 9-3
<tree datasources="10-4.rdf" flex="1" ref="urn:root" containment="http://xfly.mozdev.org/fly-rdf#list"> <treecols>
<treecol id="LabelCol" flex="1" sort="?label" label="Name" primary="true" /> <treecol id="LoCol" flex="1" sort="?location" label="Location"/> <treecol id="ColCol" flex="1" sort="?color" label="Color"/>
</treecols> <template>
<rule>
<conditions>
<content uri="?uri"/> <triple subject="?uri"
predicate="http://xfly.mozdev.org/fly-rdf#list" object="?list"/>
<member container="?list" child="?listitem"/> <triple subject="?listitem"
predicate="http://xfly.mozdev.org/fly-rdf#label" object="?label"/>
</conditions>
<bindings> <binding subject="?listitem"
predicate="http://xfly.mozdev.org/fly-rdf#color" object="?color"/>
<binding subject="?listitem" predicate="http://xfly.mozdev.org/fly-rdf#location" object="?location"/>
</bindings>
<action> <treechildren>
<treeitem uri="?listitem">
<treerow> <treecell ref="LabelCol" label="?label"/> <treecell ref="LoCol" label="?location"/> <treecell ref="ColCol" label="?color"/>
</treerow> </treeitem>
</treechildren>
</action> </rule>
</template>
</tree>
One major difference between this example and earlier ones is that Example 9-6 has three columns. The color data cannot be used for style in this tree scenario because trees do not support CSS data styling.
All generated data can be sorted automatically by clicking on the
column headers. Besides the tree parent element in the XUL, the other
main difference between this template and the one used with a listbox
in Example 9-4 is the structure directly beneath <conditions>
,
where <content>
is replaced by <treerow>
.
In Example 9-6, empty cells
were left blank.
Sometimes situations demand that missing data be represented by
something other than whitespace, such as a special character or marker.
Fortunately, multiple <rule>
tags can exist in a template, as shown in Example 9-7.
Alternate rule tags allow the display of missing data with other, more
general rules. Using alternate tags, you can set up templates that look
like conditional blocks; if the first rule is not satisfied, then the
second rule is tried, followed by the third, and so on. Example 9-7 shows this structure of multiple rules.
Example 9-7: Tree template with rules
<tree datasources="10-4.rdf" flex="1" ref="urn:root" containment="http://xfly.mozdev.org/fly-rdf#list">
<treecols> <treecol id="LabelCol" flex="1" sort="?label" label="Name"
primary="true" /> <treecol id="LoCol" flex="1" sort="?location" label="Location"/> <treecol id="ColCol" flex="1" sort="?color" label="Color"/>
</treecols> <template>
<!-- RULE 1: Row contains both a color and location. --> <rule>
<conditions>
<content uri="?uri"/> <triple subject="?uri"
predicate="http://xfly.mozdev.org/fly-rdf#list" object="?list"/>
<member container="?list" child="?listitem"/> <triple subject="?listitem"
predicate="http://xfly.mozdev.org/fly-rdf#label" object="?label"/>
<triple subject="?listitem" predicate="http://xfly.mozdev.org/fly-rdf#color"
object="?color"/> <triple subject="?listitem"
predicate="http://xfly.mozdev.org/fly-rdf#location" object="?location"/>
</conditions>
<action> <treechildren>
<treeitem uri="?listitem">
<treerow> <treecell ref="LabelCol" label="?label"/> <treecell ref="LoCol" label="?location"/> <treecell ref="ColCol" label="?color"/>
</treerow> </treeitem>
</treechildren>
</action> </rule>
<!-- RULE 2: Row contains a color and no location. -->
<rule> <conditions>
<content uri="?uri"/>
<triple subject="?uri" predicate="http://xfly.mozdev.org/fly-rdf#list"
object="?list"/> <member container="?list" child="?listitem"/>
<triple subject="?listitem" predicate="http://xfly.mozdev.org/fly-rdf#label"
object="?label"/> <triple subject="?listitem"
predicate="http://xfly.mozdev.org/fly-rdf#color" object="?color"/>
</conditions>
<action> <treechildren>
<treeitem uri="?listitem">
<treerow> <treecell ref="LabelCol" label="?label"/> <treecell ref="LoCol" label="-"/> <treecell ref="ColCol" label="?color"/>
</treerow> </treeitem>
</treechildren>
</action> </rule>
<!-- RULE 3: Row contains neither a color or location. --> <rule>
<conditions>
<content uri="?uri"/> <triple subject="?uri"
predicate="http://xfly.mozdev.org/fly-rdf#list" object="?list"/>
<member container="?list" child="?listitem"/> <triple subject="?listitem"
predicate="http://xfly.mozdev.org/fly-rdf#label" object="?label"/>
</conditions>
<action> <treechildren>
<treeitem uri="?listitem">
<treerow> <treecell ref="LabelCol" label="?label"/> <treecell ref="LoCol" label=" "/>
<treecell ref="ColCol" label=" "/> </treerow>
</treeitem>
</treechildren> </action>
</rule>
</template>
</tree>
In contrast to Example 9-6, Example
9-7 moves ?location
from <bindings>
to <conditions>
in the first <rule>
in the template, making it a required
match. To avoid breaking the template-because not all objects in the
RDF file have a ?location
value-you need to make a backup plan
for generating this template when it encounters an object without a ?location
.
This backup can be a second set of more broadly defined conditions, so
that objects that "fall out" of the first condition are picked up by
the next. See the next section for an example of using different sets
of rules.
The most important additions to Example 9-7 are
the container="?uri"
member="?listitem"
attributes on
the <template>
. These attributes specify which
container you should apply multiple rules to, and the member
is for the objects in a container that must be checked. Adding these
attributes keeps the template from dying when the data doesn't meet the
first rule. The second rule, which doesn't have a <triple>
or <binding>
to identify it, is used only when a ?location
isn't present. Instead, it automatically fills in that cell with a
hyphen (Figure 9-4).
As you can see at the top of Example 9-7, the template datasource is a file called 10-4.rdf, which contains all the data listed in Example 10-4 (in the next chapter). If you save the template listed in Example 9-7 and the RDF listed in Example 10-4, you can display the tree shown in Figure 9-4.
Example 9-7 is a
<tree>
template
that contains three rules. In Example 9-8, where
a <menubar>
is shown with three rules, all possible menu
scenarios must be covered. Table 9-2 provides a
list of these scenarios. Use scenarios like this to make sure you have
content that can be created for all the data you need represented.
Scenario | Description |
---|---|
Scenario 1 |
A The Horn Fly, Carrion Fly, and Office Fly fall into this category. |
Scenario 2 | A The Common House Fly, Stable Fly, and Face Fly fall into this category. |
Scenario 3 | A Horse and House fall into this category. |
The scenarios in Table 9-2 can be translated directly into three template rules. Scenario 1 would be the first rule because it uses the most content. Scenario 2 would be the second rule because it's missing only the location. Scenario 3 will be the final rule because it doesn't have a location or color.
Example 9-8: Menubar template with three rules
<menubar datasources="10-4.rdf" ref="urn:root" containment="http://xfly.mozdev.org/fly-rdf#list">
<template> <!-- RULE 1: Menu contains both a color and location menuitem. -->
<rule> <conditions>
<content uri="?uri"/>
<triple subject="?uri" predicate="http://xfly.mozdev.org/fly-rdf#list"
object="?list"/> <member container="?list" child="?listitem"/>
<triple subject="?listitem" predicate="http://xfly.mozdev.org/fly-rdf#label"
object="?label"/> <triple subject="?listitem"
predicate="http://xfly.mozdev.org/fly-rdf#color" object="?color"/>
<triple subject="?listitem" predicate="fly-location#location"
object="?location"/> </conditions>
<action>
<menu label="?label" uri="?listitem"> <menupopup uri="?listitem">
<menuitem label="?color"/> <menuitem label="?location"/>
</menupopup>
</menu> </action>
</rule>
<!-- RULE 2: Menu contains only a color menuitem. --> <rule>
<conditions>
<content uri="?uri"/> <triple subject="?uri"
predicate="http://xfly.mozdev.org/fly-rdf#list" object="?list"/>
<member container="?list" child="?listitem"/> <triple subject="?listitem"
predicate="http://xfly.mozdev.org/fly-rdf#label" object="?label"/>
<triple subject="?listitem" predicate="http://xfly.mozdev.org/fly-rdf#color"
object="?color"/> </conditions>
<action>
<menu label="?label" uri="?listitem"> <menupopup uri="?listitem">
<menuitem label="?color"/> </menupopup>
</menu>
</action>
</rule> <!-- RULE 3: Menu contains no color or location menuitems. --> <!-- This applies to the main menus, shown on the menubar. -->
<rule> <conditions>
<content uri="?uri"/>
<triple subject="?uri" predicate="http://xfly.mozdev.org/fly-rdf#list" object="?list"/>
<member container="?list" child="?listitem"/> <triple subject="?listitem"
predicate="http://xfly.mozdev.org/fly-rdf#label" object="?label"/>
</conditions>
<action> <!-- Create the menus across the menubar --> <menu label="?label" uri="?listitem"> <!-- Give the menu the ability to popup content --> <menupopup uri="?listitem"/>
</menu>
</action> </rule>
</template>
</menubar>
As you can see, Example 9-8 is a long XUL
section. When you create the first rule, it becomes easier, though,
because the subsequent rules are just versions of the rules above them. Figure 9-5 shows how this <menubar>
template draws the data in the 9-5.rdf datasource.
Almost any XUL element that
can be used as a container can use a template to define its inner
content. Example 9-9 shows a <box>
used as the start for a XUL template. Templates like this can create
content that doesn't look as tabular or ordered.
Example 9-9: Template implemented in a box with buttons as content
<box datasources="10-4.rdf" ref="urn:root" containment="http://xfly.mozdev.org/fly-rdf#list"> <template>
<rule>
<conditions>
<content uri="?uri"/> <triple subject="?uri"
predicate="http://xfly.mozdev.org/fly-rdf#list" object="?list"/>
<member container="?list" child="?listitem"/> <triple subject="?listitem"
predicate="http://xfly.mozdev.org/fly-rdf#label" object="?label"/>
</conditions>
<bindings> <binding subject="?listitem"
predicate="http://xfly.mozdev.org/fly-rdf#color" object="?color"/>
<binding subject="?listitem" predicate="fly-location#location" object="?location"/>
</bindings>
<action> <vbox uri="?listitem">
<button label="?label"/> <button label="?location"/>
<button label="?color"/> <splitter/>
</vbox>
</action>
</rule> </template>
</box>
The content generated in Example 9-9 includes
three <button>
s and a <splitter>
inside
a vertical <box>
. The template building process is
repeated for every object in the RDF graph, and some buttons are left
blank. The result is a window full of buttons for each piece of data,
which may get you started making heads-up displays or panel-like
applications for templates, such as flight simulators.
Once you understand the basics of templates, it is fun to see what kind of XUL you can generate from it, such as games that need to render content on the fly, spreadsheets, database front ends, or other data-driven application user interfaces.
[Back] An rdf:Bag
is a type of RDF container, but when you use the <member\>
tag, you do not have to specify whether the container is of the type
Alt, Bag, or Sequence (see "nsIRDFContainer" in Chapter 10 for more
details on working with containers in RDF). A template can only build
the values sequentially out of a container, no matter what type it is.
Thus, using an rdf:Seq
or rdf:Alt
element produces
the same visual output in these Mozilla templates.