Click here to Skip to main content
15,868,141 members
Articles / Web Development / CSS

Using XSLT to Generate a Multi-level Tree Menu from XML

Rate me:
Please Sign up or sign in to vote.
4.31/5 (9 votes)
28 Feb 20022 min read 212.7K   1.9K   46   27
A simple and generic way to use XSLT to generate a multi-level HTML tree menu from an XML source

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

XML
<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
<?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.

VBScript
<%
   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.

JavaScript
<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.

HTML
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.


Written By
Web Developer
South Africa South Africa
I live in the Northern Suburbs of Cape Town (South Africa).

Comments and Discussions

 
Questionopen some url in a new window Pin
metador0919-May-13 17:57
metador0919-May-13 17:57 
GeneralJavaScript not working Pin
sneakyhippie28-Aug-09 10:56
sneakyhippie28-Aug-09 10:56 
I've been trying to get this to work with no success. I can't even get it to work imbeding it in simple html. I used the javascript above and put the following in the body to just do a single child/parent tree. The parent is visible and the child is not, like it should be, but it won't expand.



<lable id="lblExpand" class="Expander" onclick="ExpanderClicked(event)">+
Message:


asdf = asdf


GeneralRe: JavaScript not working Pin
sneakyhippie28-Aug-09 10:59
sneakyhippie28-Aug-09 10:59 
GeneralRe: JavaScript not working Pin
sneakyhippie28-Aug-09 11:03
sneakyhippie28-Aug-09 11:03 
GeneralCross-browser compatible JavaScript-code Pin
Karl-Johan G14-Apr-08 2:09
Karl-Johan G14-Apr-08 2:09 
QuestionHow to use attribute to be a condition? Pin
mathuros_paiboon18-Jul-05 5:27
mathuros_paiboon18-Jul-05 5:27 
QuestionHow to use attribute to be a condition Pin
mathuros_paiboon18-Jul-05 5:15
mathuros_paiboon18-Jul-05 5:15 
GeneralIs it possible to create Tabular tree Pin
KrisBabu30-Jul-04 0:05
KrisBabu30-Jul-04 0:05 
QuestionBug?? Pin
HyperJ29-Oct-03 6:12
HyperJ29-Oct-03 6:12 
Generalmozilla Pin
will_mad23-Jul-03 1:52
will_mad23-Jul-03 1:52 
GeneralRe: mozilla Pin
mrameshchandra6-May-05 23:36
mrameshchandra6-May-05 23:36 
GeneralRe: mozilla Pin
scotiniotis28-Jun-07 7:58
scotiniotis28-Jun-07 7:58 
GeneralTransfom using javascript Pin
frostie23-Feb-03 22:58
frostie23-Feb-03 22:58 
GeneralRe: Transfom using javascript Pin
MS le Roux24-Feb-03 1:01
MS le Roux24-Feb-03 1:01 
GeneralRe: Transfom using javascript Pin
frostie24-Feb-03 5:02
frostie24-Feb-03 5:02 
GeneralRe: Transfom using javascript Pin
frostie24-Feb-03 5:04
frostie24-Feb-03 5:04 
GeneralRe: Transfom using javascript Pin
frostie24-Feb-03 5:30
frostie24-Feb-03 5:30 
GeneralPersistence Pin
DACS4-Jul-02 23:01
DACS4-Jul-02 23:01 
GeneralCan't get it working! Pin
13-Jun-02 23:27
suss13-Jun-02 23:27 
GeneralRe: Can't get it working! Pin
MS le Roux17-Jun-02 20:25
MS le Roux17-Jun-02 20:25 
GeneralRe: Can't get it working! Pin
StephenWilliams9-Dec-02 0:09
StephenWilliams9-Dec-02 0:09 
QuestionPictures? Pin
Domenic Denicola1-Mar-02 3:06
Domenic Denicola1-Mar-02 3:06 
AnswerRe: Pictures? Pin
MS le Roux1-Mar-02 3:15
MS le Roux1-Mar-02 3:15 
GeneralRe: Pictures? Pin
Domenic Denicola1-Mar-02 3:19
Domenic Denicola1-Mar-02 3:19 
GeneralRe: Pictures? Pin
Anand Bisht25-Nov-02 0:35
Anand Bisht25-Nov-02 0:35 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.