Browse DevX
Sign up for e-mail newsletters from DevX


Build an XML-based Tree Control with JavaScript : Page 5

Tree controls provide a hierarchical view of data and XML provides a way to structure data hierarchically, so viewing XML data as a tree structure is a natural fit. But browsers don't provide a tree control. Instead, use this mix of XML, XSLT, JavaScript, and CSS to produce an extensible HTML tree control.




Building the Right Environment to Support AI, Machine Learning and Deep Learning

How the XSLT Stylesheet Works
To begin a transformation, an XSLT processor first looks for a template that matches the root node of the document. It's customary to use the root template as the container for all the output that will follow. In the preceding stylesheet, the template matching the root is declared as follows (note that the root node sits one level higher in the document than the root element):

<xsl:template match="/"> <html> <head> <title>XML Tree Control</title> <link rel="stylesheet" type="text/css" href="xmlTree.css"/> <script type="text/javascript" src="xmlTree.js"></script> </head> <xsl:apply-templates/> </html> </xsl:template>

Each template provides two kinds of instructions: literals that the stylesheet will write without alteration directly to the result tree, and instructions that inform the XSLT processor to perform some action. You may have noticed the <xsl:apply-templates/> element above. That's an instruction to the XSLT processor to move forward and process the children of the current node. As the processor processes the node's children, it searches for templates that match those children and executes the instructions in the matching template.

There are a few things you must keep in mind when writing XSLT stylesheets.Each match attribute value in a given template is an identifier for a given node or node set. The identifier is actually an XPath expression. You build XPath expressions around the concept of a current node being processed. So, for example, when the first or root template encounters the <xsl:apply-templates/> instruction, it looks for a template that matches children of the root node. The XPath expression that matches the child of the root node is "tree" so that is the next template processed.

Similarly, when the processor encounters the <xsl:apply-templates/> instruction in the tree template, it will go off and evaluate the children of the <tree> node. The XPath expression that matches those children in the sample document is "branch", so the stylesheet applies the branch template to each <branch> node that is a child of a <tree> node. The template will not, however, be applied to any <branch> node that is NOT a child of a <tree> node (at least not yet!). The process continues until all the stylesheet has processed all the nodes in the source tree.

When writing XSLT stylesheets, bear in mind that XSLT processors apply a default template to any nodes that don't have a specific matching template. The default template automatically processes the child nodes of the given node or outputs the text content of a node if it contains no children. That's why the stylesheet for the tree control has a blank template for the <branchText> nodes above. The stylesheet already outputs the value of the <branchText> node (using the statement <xsl:value-of select="branchText"/>) and I didn't want the text duplicated in the output. The empty template tells the XSLT processor to do nothing when it encounters a <branchText> node.

The interesting parts of the stylesheet occur in the branch template:

<xsl:template match="branch"> <span class="trigger"> <xsl:attribute name="onClick"> showBranch ('<xsl:value-of select="@id"/>'); </xsl:attribute> <img src="closed.gif"> <xsl:attribute name="id">I <xsl:value-of select="@id"/> </xsl:attribute> </img> <xsl:value-of select="branchText"/> <br/> </span> <span class="branch"> <xsl:attribute name="id"> <xsl:value-of select="@id"/> </xsl:attribute> <xsl:apply-templates/> </span> </xsl:template>

The branch template creates a <span> element and adds an onClick attribute. The stylesheet gets the value for the onClick attribute from the id attribute of the <branch> node (the current node). Next, the template creates an image for each <span> element (trigger) with a unique id—the sample code uses an 'I' as a prefix and appends the id attribute value. The id attribute ensures that JavaScript (which acts on the result of the transformation) will be able to determine which trigger a user clicked so it can swap the src attribute value to display the correct image. The final <span> represents the branch to expand in the browser. Once again, sometimes it's easier to analyze what's happening in a transformation by looking at the results:

<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>XML Tree Control</title> <link href="xmlTree.css" type="text/css" rel="stylesheet"> <script src="xmlTree.js" type="text/javascript"> </script> </head> <body> <span class="trigger" onclick=" showBranch('html'); "> <img src="closed.gif" id="Ihtml">HTML<br> </span> <span class="branch" id="html"><img src="doc.gif"> <a href="#">Tags, Tags, Tags</a><br> <img src="doc.gif"> <a href="#">Hyperlinks</a><br> <img src="doc.gif"><a href="#">Images</a><br> <img src="doc.gif"><a href="#">Tables</a><br> <img src="doc.gif"><a href="#">Forms</a><br> </span> <span class="trigger" onclick=" showBranch('css'); "> <img src="closed.gif" id="Icss">CSS<br> </span> <span class="branch" id="css"><img src="doc.gif"> <a href="#">Inline Styles</a><br> <img src="doc.gif"><a href="#">Document Wide Styles</a><br> <img src="doc.gif"><a href="#">External Style Sheets</a><br> <img src="doc.gif"><a href="#">Formatting Text</a><br> <img src="doc.gif"><a href="#">Positioning Text</a><br> </span> <span class="trigger" onclick=" showBranch('javascript'); "> <img src="closed.gif" id="Ijavascript">JavaScript<br> </span> <span class="branch" id="javascript"><img src="doc.gif"> <a href="#">The Basics</a><br> <img src="doc.gif"><a href="#">Working with Images</a><br> <img src="doc.gif"><a href="#">Controlling Frames</a><br> <img src="doc.gif"><a href="#">Browser Windows</a><br> <img src="doc.gif"><a href="#">Form Validation</a><br> <img src="doc.gif"><a href="#">Handling Events</a><br> </span> <span class="trigger" onclick=" showBranch('dhtml'); "> <img src="closed.gif" id="Idhtml">DHTML<br> </span> <span class="branch" id="dhtml"><img src="doc.gif"> <a href="#">Object Detection</a><br> <span class="trigger" onclick=" showBranch('animation'); "> <img src="closed.gif" id="Ianimation">Animation<br> </span> <span class="branch" id="animation"><img src="doc.gif"> <a href="#">Path Animation</a><br> <img src="doc.gif"><a href="#">Point To Point Animation</a><br> </span> <img src="doc.gif"><a href="#">Menus</a><br> <img src="doc.gif"><a href="#">Tabbed User Interface</a><br> <img src="doc.gif"><a href="#">Trees</a><br> </span> </body> </html>

The only thing left to do is to attach the XSLT stylesheet to the xmlTree.xml XML document. Just beneath the <?xml version="1.0"?> prolog, add the following processing instruction:

<?xml-stylesheet type="text/xsl" href="xmlTree.xsl"?>

After altering the xmlTree.xml file (and saving the changes), you can load it into either IE or N7 to see the tree control work. I tested the sample code with IE 6 and Mozilla 1.3 and both browsers rendered the tree beautifully. Just make sure that all the files are in the same directory.

Thanks for your registration, follow us on our social networks to keep up-to-date