XForms/Graph Viewer

Motivation
Sometimes you need to have a form edit data structures that are recursive. In other words: a structure that references itself.

This example has nodes that have links. These links in turn point back to nodes. This is an example of a self-referential data structure. This is common when manipulating graphs. Workflow systems frequently use these structures.

Link to Working Example
Graph Editor

XML Schema
Here is a sample XML Schema with a recursive data type (a data type that includes an instance of itself):

XForms Example
This example allows you to view a graph of geographic regions.

Make sure to copy and past from the edit view of cookbook since the greater than symbols get converted.

    XForms Graph Viewer Example of viewing arbitrarily deep hierarchies with XForms v0.1  Graph Name:  

 Description:  

 Search for node id: 

Sample short-cuts: <xf:trigger> <xf:label>usa</xf:label> <xf:action ev:event="DOMActivate"> <xf:setvalue bind="current-node-id" value="'usa'" /> </xf:action> </xf:trigger> -&gt; <xf:trigger> <xf:label>minnesota</xf:label> <xf:action ev:event="DOMActivate"> <xf:setvalue bind="current-node-id" value="'minnesota'" /> </xf:action> </xf:trigger> -&gt; <xf:trigger> <xf:label>hennepin</xf:label> <xf:action ev:event="DOMActivate"> <xf:setvalue bind="current-node-id" value="'hennepin'" /> </xf:action> </xf:trigger> -&gt; <xf:trigger> <xf:label>st-louis park</xf:label> <xf:action ev:event="DOMActivate"> <xf:setvalue bind="current-node-id" value="'st-louis-park'" /> </xf:action> </xf:trigger> Current Node <xf:output ref="instance('path')/current-node-id" class="bold"> <xf:label>Current node id: </xf:label> </xf:output> <xf:output ref="//node[node-id=instance('path')/current-node-id]/links/link-id" class="bold"> <xf:label>Link type: </xf:label> </xf:output> <xf:repeat nodeset="//node[node-id=instance('path')/current-node-id]/links/node" id="repeat-node1"> <xf:trigger class="indent"> <xf:label> <xf:output ref="node-id" /> </xf:label> <xf:action ev:event="DOMActivate"> <xf:setvalue ref="instance('path')/current-node-id" value="instance('saved-data')//node[node-id=instance('path')/current-node-id]/links/node[position=index('repeat-node1')]/node-id" /> </xf:action> </xf:trigger> </xf:repeat> All Nodes: <xf:repeat nodeset="//node" id="repeat-node2"> <xf:output ref="node-id"> <xf:label>Node Name: </xf:label> </xf:output> </xf:repeat> Link Types: <xf:repeat nodeset="//links" id="repeat-link"> <xf:output ref="link-id"> <xf:label>Link Name: </xf:label> </xf:output> </xf:repeat> <xf:submit submission="save-to-file"> <xf:label>Save graph</xf:label> </xf:submit>

Discussion
Most of this is straight-forward XForms code. But there is one very tricky line. This is when you click on a node listed in the list of links and you want to make the node you just selected the current node.

The trick is is to use the position to match the index value. When the position matches the index you can set the current-node-id equal to this node.

<xf:setvalue ref="instance('path')/current-node-id" value="instance('saved-data')//node[node-id=instance('path')/current-node-id]/links/node[position=index('repeat-node1')]/node-id" />

Thanks to Fraser for the tip!