Click here to Skip to main content
6,630,901 members and growing! (16,624 online)
Email Password   helpLost your password?
Languages » XML » XSLT     Beginner

Using XSLT to generate a multi-level tree menu from XML

By MS le Roux

A simple and generic way to use XSLT to generate a multi-level HTML tree menu from an XML source.
XMLWin2K, ASP, Dev
Posted:28 Feb 2002
Views:135,124
Bookmarked:41 times
Announcements
Loading...
 
Search    
Advanced Search
Add to IE Search
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
18 votes for this article.
Popularity: 5.17 Rating: 4.12 out of 5

1

2
2 votes, 22.2%
3
2 votes, 22.2%
4
5 votes, 55.6%
5

Sample Image - TreeFromXMLUsingXSLT.gif

Introduction

This article will demonstrate a simple and generic way to use XSLT to generate a multi-level HTML tree menu from an XML source. JScript is used for expanding and contracting the menu entries. (This requires a minimum of Internet Explorer 5. I have not tested this on any other browsers.)

The XML Source

This is a subset of the source XML (full XML source is in the zip file).

<menu>
 <entry>
  <text>In-House</text>
  <url>InHouse.htm</url>
  <entry>
   <text>Web Development</text>
   <url>WebDev.htm</url>
  </entry>
 </entry>
</menu>

The XSLT

For each menu entry, the XSLT processes it, then drills down until it has processed that entry's last child.

<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
 <xsl:for-each select="//menu/entry">
  <xsl:call-template name="SubMenu">
   <xsl:with-param name="strCSS">Parent IsVisible</xsl:with-param>
  </xsl:call-template>
 </xsl:for-each>
</xsl:template>

<xsl:template name="SubMenu">
 <xsl:param name="strCSS" />
 
 <xsl:variable name="strURL" select="url" />
 
 <div class="{$strCSS}">
  <xsl:choose>
   <xsl:when test="count(entry) > 0">
    <!-- Element has children, it can be expanded -->
    <input type="hidden" id="hidIsExpanded" value="0" />
    <label id="lblExpand" class="Expander" onclick="ExpanderClicked()">+
    </label>
   </xsl:when>
   <xsl:otherwise>
    <label class="Expander">  </label>
   </xsl:otherwise>
  </xsl:choose>
  
  <a href="{$strURL}"><xsl:value-of select="text" /></a>
  <xsl:for-each select="entry">
   <xsl:call-template name="SubMenu">
    <xsl:with-param name="strCSS">NotVisible</xsl:with-param>
   </xsl:call-template>
  </xsl:for-each>
 </div>
</xsl:template>

</xsl:stylesheet>

Transforming the XML on the server

ASP is used to perform server-side transformation of the XML.

<%
   dim xmlMenu
   dim xslMenu
   
   'Get the source XML

   set xmlMenu = server.CreateObject("Microsoft.XMLDOM")
   xmlMenu.async = false
   xmlMenu.load server.MapPath("TreeFromXMLUsingXSLT.xml")
   
   'Get the XSLT to transform the XML

   set xslMenu = server.CreateObject("Microsoft.XMLDOM")
   xslMenu.async = false
   xslMenu.load server.MapPath("TreeFromXMLUsingXSLT.xsl")
   
   'Transform the source XML using XSLT

   Response.Write xmlMenu.transformNode(xslMenu)
   
   set xmlMenu = nothing
   set xslMenu = nothing
%>

Controlling the menu entries

Client-side JScript is used to first determine whether a menu entry has been expanded or collapsed, and then adjusts the selected menu entry's style settings.

<script language="jscript">
function ExpanderClicked()
{
    //Get the element that was clicked

    var ctlExpander = event.srcElement;
    var ctlSelectedEntry = ctlExpander.parentElement;
    //Get all the DIV elements that are direct descendants

    var colChild = ctlSelectedEntry.children.tags("DIV");
    if(colChild.length > 0)
    {
        var strCSS;
        //Get the hidden element that 

        //indicates whether or not entry is expanded

        var ctlHidden = ctlSelectedEntry.all("hidIsExpanded");
      
        if(ctlHidden.value == "1")
        {
            //Entry was expanded and is being contracted

            ctlExpander.innerHTML = "+ ";
            ctlHidden.value = "0";
            strCSS = "NotVisible";
        }
        else
        {
            //Entry is being expanded

            ctlExpander.innerHTML = "- ";
            ctlHidden.value = "1";
            strCSS = "IsVisible";
        }
        //Show all the DIV elements that are direct children

        for(var intCounter = 0; intCounter < colChild.length; intCounter++)
        {
            colChild[intCounter].className = strCSS;
        }
    }
}
</script>

Style setting

CSS settings are used to specify if a menu entry should be visible or hidden. The IsVisible class sets the element to be displayed, as a block element. The NotVisible class sets the element to be hidden.

body
{
   font-family: Verdana;
   font-size: x-small;
}
.IsVisible
{
   display: block;
}
.NotVisible
{
   display: none;
}
.Expander
{
   cursor: hand;
   font-family: Courier;
}
.Parent DIV
{
   margin-Left: 15px !important;
}

The last setting (.Parent DIV) indicates that only the elements below the one with the "Parent" class, will have a margin. This is to prevent the root menu entries from also having a margin.

Using images instead of + and -

It is fairly simple to show images instead of a "+" and "-" next to each entry. To do this, alter the XSLT and replace the <label> element that is next to the link, with an <img> element. In the JScript, instead of setting the InnerHTML property of the ctlExpander variable, set the src attribute to show a different image. Here is an example:

Sample Image - TreeFromXMLUsingXSLT2.gif

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

MS le Roux


Member
I live in the Northern Suburbs of Cape Town (South Africa).

Occupation: Web Developer
Location: South Africa South Africa

Other popular XML articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 25 of 26 (Total in Forum: 26) (Refresh)FirstPrevNext
GeneralJavaScript not working Pinmembersneakyhippie11:56 28 Aug '09  
GeneralRe: JavaScript not working Pinmembersneakyhippie11:59 28 Aug '09  
GeneralRe: JavaScript not working Pinmembersneakyhippie12:03 28 Aug '09  
GeneralCross-browser compatible JavaScript-code PinmemberKarl-Johan G3:09 14 Apr '08  
GeneralHow to use attribute to be a condition? Pinmembermathuros_paiboon6:27 18 Jul '05  
GeneralHow to use attribute to be a condition Pinmembermathuros_paiboon6:15 18 Jul '05  
GeneralIs it possible to create Tabular tree PinmemberKrisBabu1:05 30 Jul '04  
GeneralBug?? PinmemberHyperJ7:12 29 Oct '03  
Generalmozilla Pinsusswill_mad2:52 23 Jul '03  
GeneralRe: mozilla Pinmembermrameshchandra0:36 7 May '05  
GeneralRe: mozilla Pinmemberscotiniotis8:58 28 Jun '07  
GeneralTransfom using javascript Pinmemberfrostie23:58 23 Feb '03  
GeneralRe: Transfom using javascript PinmemberMS le Roux2:01 24 Feb '03  
GeneralRe: Transfom using javascript Pinmemberfrostie6:02 24 Feb '03  
GeneralRe: Transfom using javascript Pinmemberfrostie6:04 24 Feb '03  
GeneralRe: Transfom using javascript Pinmemberfrostie6:30 24 Feb '03  
GeneralPersistence PinmemberDACS0:01 5 Jul '02  
GeneralCan't get it working! Pinmemberchris B0:27 14 Jun '02  
GeneralRe: Can't get it working! PinmemberMS le Roux21:25 17 Jun '02  
GeneralRe: Can't get it working! PinmemberStephenWilliams1:09 9 Dec '02  
GeneralPictures? PinmemberDomenic [CPUA 0x1337]4:06 1 Mar '02  
GeneralRe: Pictures? PinmemberMarSCoZa4:15 1 Mar '02  
GeneralRe: Pictures? PinmemberDomenic [CPUA 0x1337]4:19 1 Mar '02  
GeneralRe: Pictures? PinmemberAnand Bisht1:35 25 Nov '02  
GeneralRe: Pictures? PinmemberMS le Roux1:51 25 Nov '02  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 28 Feb 2002
Editor: Smitha Vijayan
Copyright 2002 by MS le Roux
Everything else Copyright © CodeProject, 1999-2009
Web17 | Advertise on the Code Project