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.
="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">
<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
set xmlMenu = server.CreateObject("Microsoft.XMLDOM")
xmlMenu.async = false
xmlMenu.load server.MapPath("TreeFromXMLUsingXSLT.xml")
set xslMenu = server.CreateObject("Microsoft.XMLDOM")
xslMenu.async = false
xslMenu.load server.MapPath("TreeFromXMLUsingXSLT.xsl")
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()
{
var ctlExpander = event.srcElement;
var ctlSelectedEntry = ctlExpander.parentElement;
var colChild = ctlSelectedEntry.children.tags("DIV");
if(colChild.length > 0)
{
var strCSS;
var ctlHidden = ctlSelectedEntry.all("hidIsExpanded");
if(ctlHidden.value == "1")
{
ctlExpander.innerHTML = "+ ";
ctlHidden.value = "0";
strCSS = "NotVisible";
}
else
{
ctlExpander.innerHTML = "- ";
ctlHidden.value = "1";
strCSS = "IsVisible";
}
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:
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.