Home > Tutorials : XUL Tutorial : 9.5 - Advanced Rules

Previous Next

## Advanced Rules

This section describes the more advanced rule syntax.

### The Full Rule Syntax

The rule syntax described so far is useful for some datasources but sometimes you will need to display data in more complicated ways. The simple rule syntax is really just a shortcut for the full rule syntax which is described below. Like the simple rules, full rules are placed within the rule tag.

Full rules contain three child tags, a conditions tag, a bindings tag and an action tag, although the bindings tag is not always needed.

The conditions element is used to specify the criteria for matching a given resource. You can specify a number of conditions, all of which must match. In the simple rule syntax, the conditions are placed directly on the rule element itself.

If the conditions match for a resource, the content placed within the actions tag is generated. In the simple syntax, the content is placed directly inside the rule.

### Rule Conditions

When a tree, menu or other element with a datasource generates content, the template builder first finds the resource referred to by the ref attribute. It then iterates over all that resource's child resources. It applies each resource to the conditions. If the conditions match for that resource, the content in the actions element is generated for that resource. If the conditions do not match, no content is generated.

The conditions element can contain three elements. The first is the content element, which should always exist once and only once. It serves as a placeholder as the template builder iterates through the resources. It specifies the name of a variable in which is placed a reference to the root resource while the conditions are analyzed for a match. The root resource is the one specified by the ref attribute on the element containing the template.

The syntax of the content element is as follows:

    <content uri="?var"/>

The question mark indicates that the text following it is a variable. You can then use the variable 'var' within the remainder of the conditions. Of course, you can name the variable whatever you want.

The next element is the member element, which is used to iterate through a set of child resources. In RDF terms, that means a container such a Seq, Bag or Alt. Let's say you have a list of cities described in the following RDF/XML fragment:

    <RDF:Seq about="http://www.xulplanet.com/rdf/weather/cities">
      <RDF:li resource="http://www.xulplanet.com/rdf/weather/city/Paris"/>
      <RDF:li resource="http://www.xulplanet.com/rdf/weather/city/Manchester"/>
      <RDF:li resource="http://www.xulplanet.com/rdf/weather/city/Melbourne"/>
      <RDF:li resource="http://www.xulplanet.com/rdf/weather/city/Kiev"/>
    </RDF:Seq>

    <RDF:Description about="http://www.xulplanet.com/rdf/weather/city/Paris">
      <cityset:name>Paris</cityset:name>
    </RDF:Description>

    .
    .
    .

You want to display a row in a tree for each city. To do this, use the member element as in the following:

    <tree id="citiesTree" datasources="weather.rdf"
          ref="http://www.xulplanet.com/rdf/weather/cities">
      <template>
        <rule>
          <conditions>
            <content uri="?list"/>
            <member container="?list" child="?city"/>
          </conditions>
        <rule>
      <template>
    </tree>

The template builder starts by grabbing the value of the ref attribute, which in this case is http://www.xulplanet.com/rdf/weather/cities. This resource will be placed in the 'list' variable as specified by the content tag. We can then get related resources to the root resource by using the 'list' variable.

The template builder then sees the member element. It causes the builder to iterate over the children of an element. The parent is specified by the container attribute and the children are specified by the child attribute. In the example above, the value of the container attribute is the variable 'list'. Thus the parent will be the value of the list variable, which has been set to the root resource 'http://www.xulplanet.com/rdf/weather/cities'. The effect will be to iterate through the list of children of 'http://www.xulplanet.com/rdf/weather/cities'.

If you look at the RDF above, the 'http://www.xulplanet.com/rdf/weather/cities' resource has four children, one for each different city. The template builder iterates through each one, matching the child against the value of the child attribute. In this case, it is just set to the variable 'city'. So the builder will set the 'city' variable to the each child resource in turn.

Because there are no more conditions, the condition matches for each of those four resources and the builder will generate content for each of the four. Of course, the example above doesn't have any content. We'll add that later.

The next element is the triple element. It is used to check for the existence of a given triple (or assertion) in the RDF datasource. A triple is like a property of a resource. For example, a triple exists between a bookmark and its URL. This might be expressed as follows:

    A Bookmark to mozilla.org  ->  URL  ->  www.mozilla.org

This means that there is a triple between the bookmark 'A Bookmark to mozilla.org' and 'www.mozilla.org' by the URL property. The first part of this expression is called the subject, the second part is called the predicate and the last part is called the object. As a triple element, it would be expressed as follows:

    <triple subject="A Bookmark to mozilla.org"
               predicate="URL"
               object="www.mozilla.org"/>

This has been simplified a bit from the real thing. The predicate would normally include the namespace, and the subject would be the bookmark's resource id, not the bookmark's title as used here. In fact, the bookmark's title would be another triple in the datasource using the Name predicate.

You can replace the subject and object on the triple element with variable references, in which case values will be substituted for the variables. If no value is defined for a variable yet, the template builder will look up the value in the datasource and assign it to the variable.

Let's say we wanted to add a weather prediction to the city datasource. The following conditions might be used:

    <conditions>
      <content uri="?list"/>
      <member container="?list" child="?city"/>
      <triple subject="?city"
                 predicate="http://www.xulplanet.com/rdf/weather#prediction"
                 object="?pred"/>
    </conditions>

The template builder will iterate over each city as before. When it gets to the triple, it will look for an assertion in the RDF datasource for a city's weather prediction. The variable 'pred' will be assigned the prediction. The builder will repeat this for each of the four cities. A match occurs and the builder will generate content for each city that has a prediction. If the city has no prediction resource, the condition does not match and no content will be generated for that city. Note that you do not need to put 'rdf:' at the beginning of the predicate, as that part is assumed.

We could also replace the object with an in-line value. For example:

    <conditions>
      <content uri="?city"/>
      <triple subject="?city"
                 predicate="http://www.xulplanet.com/rdf/weather#prediction"
                 object="Cloudy"/>
    </conditions>

This example is similar but we specify that we want to match on 'Cloudy'. The result is that the conditions will only match for cities where the prediction is 'Cloudy'.

We can add more triples to require more matches. For example, in the example above, we might want to check for the temperature and the wind speed. To do this just add another triple which checks for the additional resource. The condition will match if all of the triples provide values.

The example below will check for an extra triple for the name of the city. It will be assigned to the 'name' variable. The condition will only match if the city has both a name and a prediction.

    <conditions>
      <content uri="?list"/>
      <member container="?list" child="?city"/>
      <triple subject="?city"
                 predicate="http://www.xulplanet.com/rdf/weather#name"
                 object="?name"/>
      <triple subject="?city"
                 predicate="http://www.xulplanet.com/rdf/weather#prediction"
                 object="?pred"/>
    </conditions>

### Generating Content

The content to generate for a rule is specified inside the action element. This should be the content for the rows of the tree, menu items, or whatever content you want to generate. Within the content, you can refer to variables that were defined in the conditions. Thus, in the weather example above, you could use the variables 'name' or 'pred' to display the city or prediction. You can use the 'list' or 'city' variables also, but they hold resources, not text, so they won't likely have meaningful values to users.

In the simple rule syntax, you use the syntax uri='rdf:*' to indicate where content should be generated. In the full syntax, you set the value of the uri attribute to a variable which you used in the conditions. Usually, this will be the variable assigned in the child attribute of the member element.

The following example shows a complete tree with conditions and an action. You can view the RDF file separately. Source RDF

Example 9.5.1: Source

    <tree id="weatherTree" flex="1" datasources="weather.rdf"
          ref="http://www.xulplanet.com/rdf/weather/cities">
      <treecols>
        <treecol id="city" label="City" primary="true" flex="1"/>
        <treecol id="pred" label="Prediction" flex="1"/>
      </treecols>

      <template>
        <rule>
          <conditions>
            <content uri="?list"/>
            <member container="?list" child="?city"/>
            <triple subject="?city"
                    predicate="http://www.xulplanet.com/rdf/weather#name"
                    object="?name"/>
            <triple subject="?city"
                    predicate="http://www.xulplanet.com/rdf/weather#prediction"
                    object="?pred"/>
          </conditions>
          <action>
            <treechildren>
              <treeitem uri="?city">
                <treerow>
                  <treecell label="?name"/>
                  <treecell label="?pred"/>
                </treerow>
              </treeitem>
            </treechildren>
          </action>
        </rule>
      </template>
    </tree>

Two columns appear in this tree, one which displays the value of the name for each row and the other which displays the value of the prediction.

If using the dont-build-content flag on a tree, replace the content element with a treeitem element.

### Adding Additional Bindings

The final element you can add inside a rule is the bindings element. Inside it, you place one or more binding elements. A binding in a rule has the same syntax as a triple and performs almost the same function. For example, in the weather example above we could add the following binding:

    <bindings>
      <binding subject="?city"
                 predicate="http://www.xulplanet.com/rdf/weather#temperature"
                 object="?temp"/>
    </bindings>

This binding will grab the temperature resource of each city and assign it to the 'temp' variable. This is similar to what a triple does. The difference is that a binding is not examined when attempting to check the conditions. This means that the city must have a name and prediction to be displayed, yet it does not matter if it has a temperature. However, if it does, it will be placed in the 'temp' variable so it can be used in the action. If a city does not have a temperature, the 'temp' variable will be set to an empty string.

(Next) Next, we'll find out how to save the state of XUL elements.

Examples: 9.5.1

Previous Next

Copyright (C) 1999 - 2004 XulPlanet.com