inflexions.com

DOM Tree Menu Part IIDOM Tree Menu Part II

IntroductionIntroduction

Although the javascript in the previous part is simple we ended with fairly complicated error prone HTML.

In this part the source, the information about the links in the menu, is written in XML and is transformed using XSLT to produce the HTML. This way you only need the write one block of the complex HTML, the XSLT logic will take care of the rest.

Download PDF version of this document. Download PDF version of this page.

BACK TO TOPBack to the top of the page

What You Need to KnowWhat You Need to Know

Knowledge of XML and XSLT.

BACK TO TOPBack to the top of the page

The XMLThe XML

The root element of the XML document is <bookmarks> and inside it every link and header is represented like this:
<entry text="CNN" href="http://www.cnn.com"/>
for the headers the 'href' attribute is left blank, href="". To represent the tree structure we're after the <entry> tags are nested inside each other. The previous HTML example in this XML format looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<bookmarks>
 <entry text="News Links" href="">
  <entry text="Internet News" href="">
   <entry href="http://www.wired.com" title="Wired News"/>
   <entry href="http://www.xmlhack.com" title="xmlhack"/>
   <entry href="http://news.cnet.com" title="CNET News"/>
  </entry>
  <entry text="General News" href="">
   <entry href="http://www.cnn.com" title="CNN"/>
   <entry href="http://abcnews.go.com/" title="ABC News"/>
   <entry href="http://news.bbc.co.uk" title="BBC News"/>
  </entry>
 </entry>
</bookmarks>

BACK TO TOPBack to the top of the page

The XSLTThe XSLT

The XSLT file contains only two templates, one for <bookmarks> and one for <entry>.

The <bookmarks> template is straight forward, it writes the standard high level HTML tags to the output and calls the template for <entry> tags ordered by their 'title' attribute.

<xsl:template match="bookmarks">
 <html>
  <head>
   <title>DOM Tree Menu</title>
   <script type="text/javascript" language="javascript">
     function showHide(divId, iconId, linkId) {

      script as shown ...

    }
   </script>
   <!-- link to external stylesheet, if you need it -->
   <link rel="stylesheet" type="text/css" href="styles.css"/>
  </head>
  <body>
   <div style="margin-left:12px">
    <xsl:apply-templates select="entry">
     <xsl:sort order="ascending" select="@text"/>
    </xsl:apply-templates>
   </div>
  </body>
 </html>
</xsl:template>

The <entry> template is a little more complex.

<xsl:template match="entry">
 <xsl:variable name="fontSize"
  select="16 - (count(ancestor::entry)*2)"/>
 <xsl:variable name="marginSize"
  select="(count(ancestor::entry)*12)"/>
 <div
  style="margin-left:{$marginSize}px;font-size:{$fontSize}px">
  <xsl:choose>
   <xsl:when test="entry">
    <a
     href="javascript:showHide('{generate-id()}',
          'icon_{generate-id()}',
          'link_{generate-id()}')"
     title="Click to expand"
     id="link_{generate-id()}">
     <img src="images/icon_plus.gif"
     name="icon_{generate-id()}"
     id="icon_{generate-id()}"
     alt="Click to expand"
     title="Click to expand"
     width="18" height="12" border="0"/>
     <xsl:value-of select="@title"/>
    </a>
   </xsl:when>
   <xsl:otherwise>
    <a
     href="{@href}"
     title="{@title }"
     id="link_{generate-id()}"
     target="_blank">
     <xsl:value-of select="@title"/>
    </a>
   </xsl:otherwise>
  </xsl:choose>
 </div>
 <xsl:if test="entry">
  <div id="{generate-id()}" style="display:none">
   <xsl:apply-templates select="entry">
    <xsl:sort order="ascending" select="@title "/>
   </xsl:apply-templates>
  </div>
 </xsl:if>
</xsl:template>

First two xsl:variables are declared, fontSize and marginSize. The deeper in the tree the <entry> tag is located the smaller the font and the bigger the margin.

count(ancestor::entry) counts the number of <entry> tag levels above the current one. For example <entry text="CNN" href="http://www.cnn.com"/> has 2 ancestors, <entry text="General News" href=""/> and <entry text="News Links" href=""/>, so the font size will be 16 - (2 x 2) = 12 and the margin 12 x 2 = 24.

The <xsl:choose> checks if the current <entry> tag has <entry> children. If it has children it's processed as a group header; adding the 'plus' icon, the showHide() javascript, title and alt text to the <a> tag. When no <entry> children are present the template process the <entry> like a normal link. The result looks the same as in the HTML in the previous part.

The last part of the template takes care of the nesting. The instruction inside the <xsl:if> is processed if there are <entry> child tags. It writes a wrapping <div> for a group of links and inside it calls the template for <entry> tags again.

BACK TO TOPBack to the top of the page

ResourcesResources

  • Source Files - The XML, XSL and an example HTML file with the Javascript.
  • Gecko DOM Reference - DOM reference with examples on the Mozilla site.
  • Jeni's XSLT Pages - To get started with XSLT don't look any further. Jeni Tennison's tutorials cover just about all you need to get you going.
  • XML.com - Loads of articles and tutorials on all things XML.
  • IBM developerWorks - Also lots of articles and tutorials on XML technologies.
  • W3C.org - Here you'll find official specifications for XML and XSLT and a host of other information.

BACK TO TOPBack to the top of the page