Build an XML-based Tree Control with JavaScript

Build an XML-based Tree Control with JavaScript

fter writing the Build an Object-Oriented Tree Control Using JavaScript article, it occurred to me that using XML as the data source for the tree would be a natural fit. I wanted to create a solution that was both maintainable and extensible. That is, I wanted to create an automated system whereby any XML document that adhered to a given grammar would easily become an HTML tree control. Essentially, I wanted to be able to view the XML document in a browser and have the browser render it as a tree similar to the TreeView control in Windows Explorer. Further, the same control should work in both Internet Explorer 6 (IE) and Netscape/Mozilla (N7).

Tree controls provide a hierarchical view of data and XML provides a way to structure data hierarchically, so it would seem that viewing XML data as a tree structure would be a natural fit. The problem is, how can you build an HTML tree control that uses XML for its data model?

The solution is to brew a mix of XML, XSLT, JavaScript, and CSS to produce an extensible HTML tree control.

Getting Started
Initially, I set about designing a JavaScript-only solution and immediately ran into problems. While N7 parses XML according to the W3C’s DOM, IE uses a proprietary ActiveX-based parser to parse XML documents. It felt like I was traveling backward in time when developers had to support different flavors of the major browsers?each with its own DOM. Rather than build a script for each browser, I decided to attack the problem from a different level.

The problem was really pretty simple. I wanted to take an XML representation of a tree and transform it into an HTML representation. Transformation was the key! One XML technology?XSLT (Extensible Stylesheet Language Transformations)?is perfect for this task. To provide an XSLT implementation you must include a number of different components in the solution:

  • the source XML document
  • an XSLT stylesheet to perform the transformation to HTML
  • a CSS stylesheet to control the look of elements in the browser
  • a JavaScript file to make the rendered control interactive

Although you have more files to manage, the modularity helps to make the code both maintainable and extensible. And both major browsers support XSLT!

Create an XML Grammar
For this solution to work properly, you have to accept some limitations on the content in the XML document. I’ll start by writing a Document Type Definition (DTD). DTDs define the content model for instances of the document type. Including a DTD makes it easier to create the XSLT file. Any document that adheres to the DTD can then be transformed by the same stylesheet. That way, should you choose to change the view of the data, you’ll only need to modify the stylesheet?not each document instance. Open your favorite text editor and enter the following:


Save the file as tree.dtd.

The DTD specifies that elements must contain 1 or more elements (the ‘+’ indicates ‘one or more’). Each element must contain a single, required element as the first child and then zero or more of either elements or elements (the ‘*’ indicates ‘zero or more’ and the ‘|’ indicates ‘or’). In addition, all elements must have an id attribute. The DTD defines the element as containing PCDATA?parsed character data. PCDATA is plain text that adheres to the rules for writing well-formed XML. The PCDATA also specifies that the element will contain no child elements. elements contain one each of and elements, in that order (the ‘,’ indicates ‘and’ and ‘in order’). The and elements also contain PCDATA, so they can’t have any child elements either.

Create an XML Source Document
In most cases, it’s easier to understand the XML grammar by looking at a document instance. Grab a new file and enter the following XML:

                     HTML                     Tags, Tags, Tags            #                              Hyperlinks            #                              Images            #                              Tables            #                              Forms            #                              CSS                     Inline Styles            #                              Document Wide Styles            #                              External Style Sheets            #                              Formatting Text            #                              Positioning Text            #                              JavaScript                     The Basics            #                              Working with Images            #                              Controlling Frames            #                              Browser Windows            #                              Form Validation            #                              Handling Events            #                              DHTML                     Object Detection            #                              Animation                           Path Animation               #                                                        Point To Point Animation               #                                          Menus            #                              Tabbed User Interface            #                              Trees            #                  

Save the file as tree.xml. The preceding file is called an instance of the tree DTD because it adheres to the grammar specified in the DTD. To validate the document?that is, to make sure that it adheres to the grammar?add a DOCTYPE declaration to the document just beneath the prolog:


You’ll need a validating parser to validate the document. I’ve been working on an XML editor, written in Java, which includes validation services. You can download the editor here.

JXEd is freeware but, be warned; it is a work in progress. To validate documents in JXEd, open the file and choose Validate from the Tools menu.

It’s important to validate your XML documents so that no errors will occur when the transformation is applied.

Create JavaScript and CSS Files
You’ll need to create the JavaScript and CSS files next. The JavaScript file contains the variables and functions to make the tree work in a browser and the CSS stylesheet controls how the browser formats the text in the tree control.

Here’s the content of the JavaScript file:

   var openImg = new Image();   openImg.src = "open.gif";   var closedImg = new Image();   closedImg.src = "closed.gif";      function showBranch(branch){      var objBranch =          document.getElementById(branch).style;      if(objBranch.display=="block")         objBranch.display="none";      else         objBranch.display="block";      swapFolder('I' + branch);   }      function swapFolder(img){      objImg = document.getElementById(img);      if(objImg.src.indexOf('closed.gif')>-1)         objImg.src = openImg.src;      else         objImg.src = closedImg.src;   }

Save the completed JavaScript file as xmlTree.js.

Here’s the code for the CSS file:

   body{      font: 10pt Verdana,sans-serif;      color: navy;   }   .trigger{      cursor: pointer;      cursor: hand;      display: block;   }   .branch{      display: none;      margin-left: 16px;   }   a{      text-decoration: none;   }   a:hover{      text-decoration: underline;   }

Save the completed CSS file as xmlTree.css.

Create the XSLT Stylesheet
XSLT?as the “Transformations” aspect of the name suggests?is a mechanism whereby your XML data is transformed into some other form. That form could be HTML, WML, SOAP, or another XML structure. This article focuses on converting the XML document containing the data to HTML. The concept is simple: you create a set of rules for the elements in your XML document (aka a stylesheet) that manipulates those elements to make them presentation-friendly. Then you apply the stylesheet to the document with an XSLT processor. The transformation can happen in place when XSLT support is built into the client, or externally, for example on your Web server. If you perform the transformation externally, you send the transformation’s result to the client. However, both IE and N7 can be used to process the XSLT instructions in place, so if you’re using one of those two browsers, you don’t need a Web server to use the tree control presented in this article.

In a nutshell, XSLT transforms your XML into a more viewable form. The original XML content is known as the source tree in the XSLT process. The output of the transformation is known as the result tree. Your stylesheet contains the rules for making the switch from source tree to result tree happen. You define those rules in XSLT templates. The XSLT engine applies the rules you define.

Here is the XSLT Stylesheet:

                                       XML Tree Control                                                                                                showBranch         ('');                        I                                          

Save the file as xmlTree.xsl.

XSLT is written in XML, so it enjoys all the benefits inherent in XML?including namespace support as shown in the preceding code. The element is a container for all of the templates in the stylesheet. The element is optional and can take several parameters that give you better control over the result tree. The method attribute takes as a value either xml, html, or text. XML is case-sensitive, so be careful how you enter names and parameter values.

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):

                           XML Tree Control                                             

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 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 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 instruction in the tree template, it will go off and evaluate the children of the node. The XPath expression that matches those children in the sample document is “branch”, so the stylesheet applies the branch template to each node that is a child of a node. The template will not, however, be applied to any node that is NOT a child of a 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 nodes above. The stylesheet already outputs the value of the node (using the statement ) 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 node.

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

                        showBranch         ('');                        I                                          

The branch template creates a element and adds an onClick attribute. The stylesheet gets the value for the onClick attribute from the id attribute of the node (the current node). Next, the template creates an image for each 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 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:

                      XML Tree Control                                           HTML
Tags, Tags, Tags
Inline Styles
Document Wide Styles
External Style Sheets
Formatting Text
Positioning Text
The Basics
Working with Images
Controlling Frames
Browser Windows
Form Validation
Handling Events
Object Detection
Path Animation
Point To Point Animation
Tabbed User Interface

The only thing left to do is to attach the XSLT stylesheet to the xmlTree.xml XML document. Just beneath the prolog, add the following processing instruction:


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.

Embed the Tree in an HTML Document
In most cases, the tree control will be a component in another Web page. The transformation above creates the tree for viewing in a browser but, usually, you’ll want to surround the tree with other content.

Both IE and N7 use the same mechanism for embedding external content?the

Page Content Here

In my opinion, Mozilla renders this HTML file correctly but IE doesn’t. IE insists on displaying a scrollbar for the