When you think ASP, think...
Recent Articles xml
All Articles
ASP.NET Articles
Related Web Technologies
User Tips!
Coding Tips
spgif spgif

Sample Chapters
JavaScript Tutorials
MSDN Communities Hub
Official Docs
Stump the SQL Guru!
XML Info
Author an Article
spgif spgif
ASP ASP.NET ASP FAQs Feedback topnav-right
Print this page.
Published: Wednesday, July 25, 2001

A Dynamic Tree Menu System, Part 3

By Sam Reynoso

  • Read Part 1
  • Read Part 2

  • In Part 2 we looked at the needed code for menu.asp from a very high-level viewpoint. In this part, we'll delve into the workhorse of the ASP page, the DisplayNode() function!

    - continued -

    A Closer Look at DisplayNode()
    DisplayNode() is the workhorse of menu.asp. It is responsible for traversing the XML tree and generating the appropriate HTML for each node of the tree. The routine calls itself recursively whenever it finds a node that contains children.

    The subroutine takes the following four parameters: objNodes, iElement, sLeftIndent, and arOpenFolders. The first, objNodes, is the collection containing the children of the root element in the XML file. The next parameter, iElement, contains an integer representing a tally of how many nodes have been displayed so far. This parameter is passed by reference so that it can be updated on each call to the subroutine. It also permits us to have the final value available to us when we finish traversing the XML tree. sLeftIndent is used to pass a string by reference that contains HTML formatting needed to properly display the indentation of menu items. The final parameter, arOpenFolders, is an array that we populated at the top of menu.asp. As you recall, this array is used to indicate which folders should be displayed as expanded by default.

    When we call DisplayNode(), we iterate through each of the child nodes passed in the objNodes parameter. We also perform some checks to see:

    1. Whether or not this node has children,
    2. Whether or not this is the last node in the list, and
    3. We ensure that the node type we are examining is of type NODE_ELEMENT. Our code ignores other valid XML node types including NODE_TEXT. This was done to simplify the code needed to traverse the XML tree.

       For Each oNode In objNodes
          'Find out if current node has children
          bHasChildren = oNode.hasChildNodes
          'Find out if the current node is the last member
          'in the list or not
          if not(oNode.nextSibling is nothing) then
             bIsLast = false
             bIsLast = true
          end if
          'Ignore NODE_TEXT node types
          if oNode.nodeType = NODE_ELEMENT Then

    Next, we store the values of the attributes found in the current node.

            'Get the display value of the current node
            sAttrValue = oNode.getAttribute("value")
            'Get the type of the current node Folder/Document
            sNodeType = lcase(oNode.getAttribute("type"))
            'Determine if folder is open by default
            bForceOpen = fnInArray(sAttrValue, arOpenFolders)
            sURL = oNode.getAttribute("url")

    We treat document nodes differently than folder nodes. Document nodes do not contain children and they display a different icon.

    if (sNodeType = "document") then
      Dim strIcon
      strIcon = fnChooseIcon(bIsLast, sNodeType, bHasChildren, bForceOpen) %>
      <table border="0" cellspacing="0" cellpadding="0" width="100%">
         <tr valign="bottom">
            'Display the proper indentation formatting
            Response.write sLeftIndent
            'Now display the document
            <td width="31">
              <img src="images/<%=strIcon%>"
                 width="31" height="16" border="0">
            <td nowrap class="node">
                <a href="<%=sURL%>" target="basefrm"><%=sAttrValue%></a>

    Folder nodes have almost the same code as document nodes, however folder nodes are clickable and therefore contain some additional code to handle this. Folder nodes also have children, so we insert code to support this. Finding child nodes requires another call to DisplayNode() to process all the children.

    If bHasChildren Then
       'Increment the element ID so that the child will have an
       'ID that is different from the parent 
       iElement = iElement + 1
       <table border="0" cellspacing="0" cellpadding="0" width="100%">
          <tr valign="bottom" class="LEVEL<%=iElement%>" id="<%=iElement%>"
             style="display:<%if (fnInArray(sAttrValue, arOpenFolders)=false) then%>
                    end if%>">
                'First store the indentation code
                sTempLeft = sLeftIndent
                'We don't want to indent the first node on our tree
                'so only generate indent code if this not the root menu item
                if (iElement > 1) then
                   sLeftIndent = fnBuildLeftIndent(oNode, bIsLast, sLeftIndent)
                end if
                'Call this subroutine again to process the submenu item
                DisplayNode oNode.childNodes, iElement, sLeftIndent, arOpenFolders
                'We're popping the stack, so reset the value of sLeftIndent to
                'what it was before we went into the DisplayNode() subroutine above
                sLeftIndent = sTempLeft
    End If

    The other ASP supporting routines fnChooseIcon(), fnInArray(), fnBuildLeftIndent(), and sbShowXMLParseError() are not discussed in this article, but are fully documented in the source code.

    Now that we've completed our (exhaustive) examination of the DisplayNodes() function, let's turn our attention to the client-side JavaScript code. In Part 4 we'll look at the client-side code in menu.asp and wrap up the article.

  • Read Part 4!

  • ASP.NET [1.x] [2.0] | ASPFAQs.com | Advertise | Feedback | Author an Article