devxlogo

Salvage Your Client-Side JavaScript Menus in ASP.NET Using XML/XSLT

Salvage Your Client-Side JavaScript Menus in ASP.NET Using XML/XSLT

or the past several years, creating client-side JavaScript based menus using the browser’s DOM capabilities has been a popular way for developers to implement Web site navigation?so popular that there are now hundreds of Web sites offering free or commercial versions of such JavaScript menus. The complexity of such menus ranges from simple boxes that change style when users hover over menu items with the mouse to sophisticated dynamic versions that change content in response to other client-side events.

Despite the range of visual styles and content, these JavaScript-based menus tend to work the same way. The site designer first organizes a menu hierarchy in terms of HTML tags such as

, , etc. Each item or group of items contains CSS “class” attributes, which the JavaScript code uses to creates various styles and effects. Extending such menus requires editing the often-cryptic HTML or JavaScript code?or both. Site designers must learn to find their way around the code heuristically to add the new items unless they’re willing to spend an excessive amount of time figuring out the entire code and layout scheme.

Microsoft took server programming in their ASP.NET product to a higher level than in its earlier ASP product, in that developers can now process browser events (the consequences of actions taken by the user running a browser on a client machine) on the server?even though those events are raised on the client. ASP.NET effectively reduces an array of DOM events to a handful of server events with the runat=”server” attribute. Each of these “server controls” renders the JavaScript code within the page required to forward events back to the server. Developers can include their own JavaScript client-side event-handling script, but to do so they must use specific instructions in the server control’s script so the script will run (see the MSDN topic “ASP.NET Server Control Event Model” for more information). In effect, the two ASP products provide opposite models. The older ASP model gives developers complete control at the price of having to write all the event code manually, while the ASP.NET model automates much of the event-handling code at the price of developers having to intervene to regain manual control. Still, one can justify the loss of client-side control introduced by the ASP.NET model by the additional functionality offered by the server controls.

Reusing Existing Client-side JavaScript Menu Code
Given these opposite models, how can you reuse existing client-side JavaScript menu code in ASP.NET? Here are some ideas:

  • Include the HTML/JavaScript code in the server-side .aspx file. This effectively means bypassing the ASP.NET server event code and going back to the ASP model, because you cannot use the runat=”server” attribute for the
    tag?which is the backbone of a page in the ASP.NET model. You have to adopt the earlier model to prevent the new server-side controls from rendering additional content on the page. Unfortunately, it’s difficult to implement the HTML/JavaScript code in this way because it requires careful analysis to identify what can and cannot be included within an object with a runat=”server” attribute.
  • Use Response.Write to render the HTML/JavaScript code. You can employ this technique in the Page_Load event handler to render the entire HTML/JavaScript code verbatim on the browser. However, this method doesn’t take advantage of ASP.NET’s server processing methodology?and the resulting menu is just as hard to modify as the original code.
  • Write customized server controls that include the client side HTML/JavaScript code as part of their rendering utilities. This is, of course, plausible; however, it requires an in-depth knowledge of low-level server control programming. Furthermore, the menu form remains as complex as before?not to mention that you must recompile the code every time you modify the menu (see IE Web Controls for more information on writing Web server controls from scratch).
  • Use existing controls to simulate a custom menu. In their popular ASP.NET book, Alex Homer and Dave Sussman, et. al. present a case study that creates an XML-based menu using a DataList server control. Their menu works fine for menus one or two levels deep; however, nesting DataList controls to create menus of arbitrary depth is not trivial. For an arbitrary depth menu I’ve found it’s better to use a TreeView control (from Microsoft’s downloadable IE Web Controls, binding it to an XML file containing the hierarchal menu. The TreeNode element that makes up the individual items of this control can contain children of its own type, letting you nest elements to any arbitrary depth. Using a TreeView works fine for Windows Explorer-like GUIs, but severely limits the styles you can produce unless you are willing to re-write the code-behind that renders the control. Furthermore, all events raised by this control are processed on the server by default, which requires server trips for actions that you’d expect to happen on the client, such as selecting, expanding and collapsing nodes.

A New Approach
The upshot is that you need a new approach. The objective of this article is to create a general menu construction technique rather than a specific implementation that may or may not apply to a given HTML/JavaScript template. The desired features are:

  • To present the menu hierarchy in a simple form such as an XML schema?similar to that in the TreeView control, allowing arbitrary depth with minimal and straight-forward modification.
  • To create a menu construction technique applicable to any existing complex HTML/JavaScript code as is?thereby allowing reuse of the existing code.

This article presents such a general technique, along with an example that employs the technique to create client-side JavaScript menus in ASP.NET. You can download the sample code for this article to follow along.

XML and XSLT to the Rescue
The basic idea here is to use XSLT to create an existing HTML/JavaScript template by transforming XML documents that adhere to a simple schema accommodating a menu hierarchy. To modify or extend the menu, you need merely modify the XML file rather than the complex combination of HTML and JavaScript code, which is the output of the transformation.

?
Figure 1. Desired Menu Structure: Each menuItem element may have a collection of menuItem children. The leaf elements (the last children in a branch) hold URLs for redirecting the browser.

Figure 1 shows a desired menu structure where the element has children of its own type?similar to the TreeNode element of the TreeView control. The leaf elements (the last children in a branch) each point to a URL where the browser is directed when users click a leaf. Because elements can have children of their own type, it is not possible to show a schema diagram for this tree.

Clearly, this is an easier structure to modify and extend than the convoluted combination of HTML tags and/or JavaScript arrays, particularly for complex menus such as Hiermenus. XSLT does the hard work of transforming the XML tree to the desired HTML/JavaScript code. This fits well with ASP.NET’s server-based methodology. You can execute the transformation logic in the page-rendering code (the Page_Load event handler) to render the results on the page during page construction. Moreover, the technique is generic, and you can apply it to any HTML/JavaScript template.

A Short Example
Here’s an example that elucidates the methodology. First, you need an XML representation of the menu tree shown in Figure 1. The following XML represents an example menu.

                                                                                                                                           

I made a slight modification in the element name from the generic XML tree shown in Figure 1 by changing the top level element to . This was required by the particular HTML/JavaScript menu template used as you’ll see shortly. To add new nodes you simply add properly nested elements. All elements require a text attribute that displays the text printed on the item when the menu is rendered. The elements without children identify the actual links and therefore require an href attribute pointing to the URL of the page you want the browser to navigate to when a user clicks the menu item. Notice that while the starting XML tree and the resulting HTML/JavaScript template could be anything, the methodology remains the same. The XSLT transformation handles the details and outputs the correct HTML and JavaScript combination for your particular menu.

For this example, I’ve used Cezary Tomczak’s XulMenu. His menu accommodates arbitrary depth and is nicely tied to CSS styles. Despite this choice, you can follow the same logic to produce output that mimics any JavaScript menu system; in other words, it doesn’t matter which menu system you’re currently using, you can write a suitable XSL transformation for any of them. The HTML/JavaScript for a XulMenu looks like this:

   Button1   
?
Figure 2: Example XulMenu: Here’s how the example menu looks when rendered in a browser.

The top level in this menu has a class=”button” attribute that ties the menu to the “button” style defined using CSS. A menu item with children has one or more

tags with the class=”section” attribute. The menu item with children displays an arrow image. Clicking on these items toggles them between their expanded and collapsed forms. Menu items with no children are simple tags with class=”item” for their style. These are the leaf items that redirect the browser to a specific URL when a user clicks them. You can add additional menu items and nested menu items by including additional and
tags in the same manner. Figure 2 shows a clip of this menu as rendered in a browser.

Even though this is a simple menu, modifying it isn’t trivial; you must add and

tags with the proper classes and correct nesting to generate the desired menu?in other words, the form is simply hard to modify. It would be far easier to modify the simpler XML tree form presented earlier and let XSLT rules take care of the transformation. The following XSLT file does exactly that:
                                    

The first item matches the element in the XML file and outputs the root and tags and the main

tag required by the HTML/JavaScript template. This
must have an id=”menu1″ and class=”XulMenu” attributes required by the template. It also creates a single
element for the table with id=”menu1″ and class=”bar” attributes?again as required by the HTML/JavaScript template. The line ensures that all children of the XML element are further transformed according to their own XSLT rules.

The next XSL template matches the XML element and outputs a

element with a class=”section” attribute as required by the HTML/JavaScript template. It also ensures that any nested elements are further processed by the XSL template by calling (like calling a recursive function). Because the element will always have children, the template outputs the
element automatically.

Transforming the XML element is a bit more complex because this element may or may not have children of its own type. If it does, the template renders the element to display the arrow image as well as a

element to hold the child elements. Otherwise it creates a leaf element with its href attribute set to the href attribute of the XML element.

ASP.NET Implementation
The best way to implement the menu transformation in ASP.NET is to take advantage of customized server controls. These are similar to the server-side #include directives except that they can have their own interfaces. You embed them in the page using the @ Register directive. This example uses a control called left (defined in left.ascx in the downloadable code), which appears on the left border of all pages in the site and contains the menu implementation. Here’s the code for the left.ascx file:

         

The literal server control with the id=”menu” attribute is a placeholder and will be bound to the rendered HTML/JavaScript menu (the output of the XSLT transformation). Here’s the partial code-behind for this control showing how binding occurs in the Page_Load event handler:

   using System.Xml.Xsl;   using System.IO;   using System.Xml.XPath;      public class left : System.Web.UI.UserControl   {      protected System.Web.UI.WebControls.Literal menu;             private void Page_Load(object sender,          System.EventArgs e)      {         // Put user code to initialize the page here         string currPath = Request.PhysicalPath;         string xmlPath = currPath.Substring(0,             currPath.LastIndexOf("\")) + "\menu1.xml";         string xslPath = currPath.Substring(0,             currPath.LastIndexOf("\")) + "\menu1.xsl";         XslTransform trans = new XslTransform();         StringWriter sW = new StringWriter();         XPathDocument mydata = new XPathDocument            (xmlPath);         trans.Load(xslPath);         trans.Transform(mydata, null, sW, null);         menu.Text = sW.ToString();     }

Notice that you have to reference the Xsl, IO, and XPath namespaces to access the required objects. The sample menu resides in the file menu1.xml and the XSL transformation shown earlier in the file menu1.xsl. You could (and should) add validation code to validate the XML and XSL schemas and catch exceptions. The remaining code uses an XslTransform to transform the XML file into the HTML/JavaScript form, and the last line binds the result to the literal server control with the id=”menu” attribute. It’s important to understand that you can modify the menu without modifying this code, as long as you don’t change the name of the literal control or move the XML or XSLT files.

Caching
Performance is always an important issue in Web applications. While performance may not be critical in an intranet application running on fast Ethernet, for large-scale Internet applications you wouldn’t want the server to execute the transformation every time a user requests a page. Creating the HTML/JavaScript form of the menu requires two I/O operations and an XSLT transformation, which may be intensive for complex menus. Fortunately, ASP.NET provides the page directive @ OutputCache, which lets you cache the control output after the first request, and use the cached copy for subsequent requests. To implement caching, add this directive to the left.ascx file shown earlier:

   

So, you’ve seen a general XML and XSLT technique that you can use to simplify the process of creating and maintaining menus, yet still salvage your existing HTML/JavaScript client-side menus in ASP.NET. The technique involves organizing menus into a simple XML tree where menu items can nest children of their own type in any arbitrary depth. Then, you create an XSLT file to transform the XML file into your preferred flavor of HTML/JavaScript. Finally, you eliminate the overhead of recreating the menu for each request by caching the XSLT output. By using this technique JavaScript menu vendors and users can migrate their existing ASP code to ASP.NET with minimal effort.

devxblackblue

About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist