Building Hierarchical Trees

A template may be used to generate hierarchical trees. This works just like with recursive generation using the content builder. Each level of the tree is created using a successive iteration of the template build process. If the items are containers, the tree builder will mark the right rows as containers, so that they can be opened and closed with the small icon twisties on the left of the column. Remember to make the left column the primary column for these to appear.

To be able to do this, the tree builder must know that an item is a container. With an RDF datasource, this would usually be an RDF container such as a Seq and the tree would display its children. For an XML datasource, the tree might display a node's children as the children in the tree, making the tree display a hierarchy similar to that in the XML document. Or, with more complex XPath expressions, a template could display a tree where the hierarchy wasn't directly like the XML document.

If a node is a container, the tree item becomes a container, and the user may open the row by double-clicking it. Note that this test is done on the member value not the reference value. For instance, in the photo example, we have a container 'http://www.xulplanet.com/rdf/myphotos' with three photos. Three results will be generated from a simple rule with no extra conditions. It is the result, or the photo, that will be checked, not the container of photos. Since a photo isn't a container, the tree rows will not become containers, so you will not be able to open them. As the rows are not containers, the tree builder does not recurse to find additional data. The tree builder creates rows lazily, so a closed container will not have any data generated inside in it until the row is opened. When the user opens the tree row, the next level of rows are generated from the template and displayed in the tree. Similarly, when the user closes a tree row, the rows inside it are removed, such that they will have to be generated again the next time the row is opened.

If you want to put rows inside the photo rows, you will either need to make each photo resource a container (for this RDF datasource, this will usually be an RDF Seq), or use the containment attribute to specify additional properties that indicate containership. If a particular photo had a value for one of the properties listed in the containment attribute, it would be accepted as a container, and the user could open the row. When the user opens the row, the template will be re-examined for results using the photo as the starting point instead of the top level ref value.

Here is an example for the streets datasource:

<tree flex="1" datasources="template-guide-streets.rdf"
      ref="http://www.xulplanet.com/rdf/myneighbourhood" flags="dont-build-content"
      xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
  <treecols>
    <treecol id="address" primary="true" label="Address" flex="1"/>
    <treecol id="floors" label="Floors" flex="1"/>
  </treecols>
  <template>
    <rule rdf:type="http://www.xulplanet.com/rdf/House">
      <treechildren>
        <treeitem uri="rdf:*">
          <treerow>
            <treecell label="rdf:http://www.xulplanet.com/rdf/address"/>
            <treecell label="rdf:http://www.xulplanet.com/rdf/floors"/>
          </treerow>
        </treeitem>
      </treechildren>
    </rule>
    <rule>
      <treechildren>
        <treeitem uri="rdf:*">
          <treerow>
            <treecell label="rdf:http://purl.org/dc/elements/1.1/title"/>
          </treerow>
        </treeitem>
      </treechildren>
    </rule>
  </template>
</tree>

The first rule is for the houses as indicated by the rule's condition and the second rule is for the streets. As shown in the snippet of the data below, the street is a Seq, so it will become a container. The houses are not containers, so they will not have children in the tree.

<rdf:Bag rdf:about="http://www.xulplanet.com/rdf/myneighbourhood">
  <rdf:li>
    <rdf:Seq rdf:about="http://www.xulplanet.com/rdf/marion"
               dc:title="Marion Street">

The result is a two level tree with two columns.

For an XML source, a container is a node in the XML document that has children. In this example, the two group elements are displayed at the first level. The individual people are displayed at the next level of the tree as the builder recurses. In this example, we only need to use one rule.

<tree datasources="people2.xml" ref="*" querytype="xml"
      rows="10" flags="dont-build-content">
  <treecols>
    <treecol id="name" primary="true" label="Name" flex="1"/>
  </treecols>
  <template>
    <query expr="*"/>
    <action>
      <treechildren>
        <treeitem uri="?">
          <treerow>
            <treecell label="?name"/>
          </treerow>
        </treeitem>
      </treechildren>
    </action>
  </template>
</tree>