Use XML to drive a DHTML menu

Populating your menus from an XML file that can be dynamically refreshed on every page allows you to mix common elements with user- and page-specific elements. This approach lets you build a unified menu without declaring all the possible permutations.

If you've used a DHTML menu script, you know that one of the things you need to provide is a list of the menu items that will make up the menus themselves. Although providing a hard-coded list or array for small or uncomplicated sites is relatively trivial, this task becomes more complex on an enterprise-scale application. In those kinds of applications, you may want to vary the menu options depending on a variety of factors, such as:
  • Logged in User/Guest account.
  • Groups the user is a member of.
  • Which part of the site the user is in.
  • Whether the user has any special responsibilities.
  • Whether the user is in a different mode, such as an edit mode.

We could create a separate hard-coded array for each possible combination in our application, but you can see how this would soon become unmanageable. Also, all the permutations have to be downloaded to the client side, so the download could quickly become significant.

Dynamically creating the menu elements
The obvious solution to this issue is to dynamically create the menu elements within your application using logic similar to the following:
if user = GUEST then
    ADD Login
    ADD LogOut
    ADD Company Info
    ADD Company Info -> Accounts
    ADD Company Info -> Phone Book
end if

The creation of a menu could be the outcome of several parts. For example:
  • Different parts of the application code, such as that shown above
  • From a data source; for instance, a list could exist in a database for each user group
  • Some standard components, such as a Home link

The final menu may be defined exclusively by one of these or most likely by combining the items provided by each part. Once this file has been generated, it can be dynamically included in the final output that is sent back to the client browser to be rendered as part of the user interface. Many variants of common DHTML menu scripts allow the structure to be defined in this way, usually from a database.

What about XML?
With the advent of XML as a way to transport data between the server and the client browser, we have another method of providing the menu structure to the end user. This approach offers several benefits:
  • The menu building is now a client-side activity, thus improving server utilization.
  • We can refresh the XML file when needed rather than every time we click an internal link or refresh the page.
  • The data is now in a separate file and is significantly easier to read and amend than when embedded within code.

The CoolMenus DHTML menu script
When I reworked my personal site, I went looking for a simple-to-use DHTML menu script I could modify to suit my exact requirements. I settled on Thomas Brattli's CoolMenus script for my site. With a little modification, it met my needs well.

The same concepts presented here would apply to any other DHTML menu script you may already have or be considering. However, this script in its initial form contains the menu items in a hard-coded format. Since the requirement for this article is to use XML to drive the menu to provide maximum flexibility, we need to make some changes for it to take its data from XML.

Modifying the menu to support XML
Looking at the script, you'll see that we can leave the bulk of the code unchanged. This also means that the core menu functionality won't need to be tested again. All that is required is an XML processor that will process a provided XML file and then use its contents to populate the data structure from which the menu is actually built using the menu's current functionality.

Creating the format of the XML file
The following is an example of the original hard-coded menu script, where a function is called with parameters to generate each menu element:
// oM.makeMenu('','','','')
oM.makeMenu('m1','','About Me','/about/');
oM.makeMenu('m2','','My CV','/cv/');
oM.makeMenu('m4','m2','PDF Version','/cv/cv.pdf');
oM.makeMenu('m5','m2','HTML Version','/cv/cv.html');

The elements that make up the structure or tree of the menu are:
  • ID—This is a unique reference of each element that must begin with a letter to avoid issues in some browsers.
  • PARENT ID—This is a reference to the parent element of this element; if null, it's a top-level menu element.
  • LABEL—This is the text to be displayed in the user interface.
  • URL—This is the URL to the item referred to in the label.

As you can see from the example, the URL attribute can refer to many elements—in this case, a directory, an Adobe PDF file, or an HTML page. For ease of use, our XML file will be defined exactly like the data structure shown above, so the format of our XML file looks something like the one in Listing A.

Processing the XML file
All we have left to do is create a function that loads the XML file and then use it to generate the function calls to build the menu in the same way that a hard-coded menu would. For this example, we'll assume that the users will be using Internet Explorer 5.5 or higher, with JavaScript for client-side scripting. To create and configure our XML object, we used the following code:
// create an instance of an XML object
varxmldoc = new ActiveXObject("Microsoft.XMLDOM");
// ensure that we process it all before carrying on with the code
xmldoc.async = false;

If you intend to provide support for non-IE browsers, you'll need to modify this part of the code as appropriate for the browser you're supporting.

Now that we have a reference to our XML object, we need to load the XML file into it. The file is contained in the variable url_xmlFile. Using this object, it's possible to pull out all the menu items contained in the XML file into an array. The items are identified by the menuitem tag:
// load the specified XML File
// pull all the menuitem elements from the XML into an array
varmenuItems = xmldoc.getElementsByTagName("menuitem");

After we have the items in an array, we should be able to loop through them and use them to provide the parameters for the standard functionality of the DHTML menu. There are two key differences between the hard-coded script above and our XML sample. First, for top-level menu items, we've used a zero in the XML file as opposed to the null in the original code. Second, we haven't prefixed the menu element numbers in the XML file with an alphanumeric, so we'll need to handle both of these within our function. Taking this into consideration, we end up with a script that looks like the one in Listing B.

We can now replace the hard-coded menu item part of the script with our new dynamic XML processor and leave the surrounding code that is specific to the DHTML menu script untouched.

Menu elements provided
Using this approach, we can provide the menu elements in an XML file. Once it is combined with the unchanged remainder of the CoolMenus script, we have a working DHTML menu driven by XML.

This article should provide a sufficient base for you to begin using the technique within your own applications. Note that refreshing the XML file depends on a variety of factors that are specific to your application, so I didn't cover that aspect here. I'll also leave it up to you to determine how to produce the XML file you use.

Editor's Picks