TruerWords Logo
Google
 
Web www.truerwords.net

Search TruerWords

Welcome
Sign Up  Log On

XUL Templates with Multiple Rules

I spent two days last week banging my head against an XUL template with multiple rules. My goal was a tree view which showed folders, nested folders (to any depth), and files within those folders.

Summary:

Looking for a quick answer? Ok: all the rules in a multi-rule template must use the same variables, no matter what they're matching. You can't add new variables after the first rule.

As I explained in a follow-up to this article, the real problem is that this fact is (apparently) undocumented.

Update:

Neil Deakin posted a reply in the discussion area, with a slight correction to my 'discovery'.

There was no problem grounding the 'folders' from the RDF datasource. That was functioning correctly before I even started.

In the RDF, an element representing a folder could have two types of child node (two different types of assertion): "RKM:folders" (which would point to a Seq listing that folder's sub-folders) and "RKM:files" (which would point to a Seq listing the files in that folder).

The tree would show a "folder" as a container if it had a "RKM:folders" assertion (outward pointing arc), or if it had a "RKM:files" assertion, or both. (To show something as a container means it would include the flippy triangle to expand the item. Folders without subfolders or files would not have the flippy triangle because they're empty.)

The first rule in my template was already there and functioning properly, to display the folders and subfolders. Here's how the whole tree started out (this is simplified a little from what I was actually using, but it's close enough):

<tree id="sample.sidebar.tree_groups"
   datasources="sampledata.rdf" ref="urn:sample:root"
   containment="http://www.mozilla.org/sample-rdf#groups"
   rows="6" flex="1" seltype="single"
   hidecolumnpicker="true" enableColumnDrag="false">
   
<treecols>
      
<treecol flex="1" id="group_name" label="groups" primary="true"/>
      
<treecol id="group_id" label="ID" collapsed="true"/>
      
<treecol id="datatype" labe="Type" collapsed="true"/>
   </treecols>
   <template>
      <rule>
         <conditions>
            <content uri="?uri" />
            
<triple subject="?uri"
                    predicate="http://www.mozilla.org/sample-rdf#groups"
                    object="?groups"/>
            <member container="?groups" child="?group"/>
            
<triple subject="?group"
                    predicate="http://www.mozilla.org/sample-rdf#label"
                    object="?text"/>
            
<triple subject="?group"
                    predicate="group://www.mozilla.org/sample-rdf#id"
                    object="?groupid"/>
         </conditions>
         <action>
            
<treechildren flex="1">
               
<treeitem uri="?group">
                  
<treerow>
                     
<treecell label="?text"/>
                     
<treecell label="?groupid"/>
                     
<treecell label="group"/>
                  </treerow>
               </treeitem>
            </treechildren>
         </action>
      </rule>
   </template>
</tree>

The important part, of course, is the conditions element in the rule. From the starting point, it looks for a groups assertion, and (if one is found) assigns it to the ?groups variable. Then, it's told to treat the element at the end of that arc as a container (seq, bag, or alt... it doesn't care), and the rest of the conditions apply to each element it finds in the container (a Seq, in my case): the member of the container must have a "label" and an "id", which are then assigned to variables.

The second rule seemed like it should be very simple! I wanted to do basically the same thing as for the first rule, but this time it would be matching files instead of groups. A copy-and-paste with a quick edit produced this:

      <rule>
         <conditions>
            <content uri="?uri" />
            
<triple subject="?uri"
                    predicate="http://www.mozilla.org/sample-rdf#files"
                    object="?files"/>
            <member container="?files" child="?file"/>
            
<triple subject="?file"
                    predicate="http://www.mozilla.org/sample-rdf#title"
                    object="?title"/>
         </conditions>
         <action>
            
<treechildren flex="1">
               
<treeitem uri="?file">
                  
<treerow>
                     
<treecell label="?title" properties="File"/>
                     
<treecell label="?file"/>
                     
<treecell label="page"/>
                  </treerow>
               </treeitem>
            </treechildren>
         </action>
      </rule>

Simple enough, right? Yeah, except it didn't work.

I eventually figured out that I had to update the containment attribute in the tree tag, to specify that the predicate "http://www.mozilla.org/sample-rdf#files" should be treated as a container, so that when the groups rule matched the row would have the flippy triangle for exansion. (Just add a space at the end of that attribute, and type in the second predicate right after the first one.)

Reload the XUL file and... nuts. Now I get the flippy triangle, but the files still aren't being listed.

Let's make a long story a little shorter. I tried a zillion combinations, and eventually discovered that the template renderer will only use variables in the second rule that were also used in the first Tree example. rule. New variable names are ignored. So, even though the second rule is matching files, and the predicates can be changed (as above), the rule's variables still have to look like you're matching groups.

Yes, I think that's ridiculous.

Here, finally, is the rule that works. Compare it with the rule that didn't work, just above, and the rule for matching groups above that (which did work).

      <rule>
         <conditions>
            <content uri="?uri" />
            
<triple subject="?uri"
                    predicate="http://www.mozilla.org/sample-rdf#files"
                    object="?groups"/>
            <member container="?groups" child="?group"/>
            
<triple subject="?group"
                    predicate="http://www.mozilla.org/sample-rdf#title"
                    object="?text"/>
         </conditions>
         <action>
            
<treechildren flex="1">
               
<treeitem uri="?group">
                  
<treerow>
                     
<treecell label="?text" properties="File"/>
                     
<treecell label="?group"/>
                     
<treecell label="page"/>
                  </treerow>
               </treeitem>
            </treechildren>
         </action>
      </rule>

I wrote to Nigel to tell him what I'd discovered. He was surprised, amused, impressed, and or disgusted enough to suggest I write it up. (Which, if you know me, you know I was going to do anyway.)

Page last updated: 11/3/2004



TruerWords
is Seth Dillingham's
personal web site.
More than the sum of my parts.