Creating a multi-level menu for umbraco

I am trying to create a layered CSS menu for a website that I am making in umbraco's content management system.

I need to build it in order to have the following structure:

<ul id="nav"> <li><a href="..">Page #1</a></li> <li> <a href="..">Page #2</a> <ul> <li><a href="..">Subpage #1</a></li> <li><a href="..">Subpage #2</a></li> </ul> </li> </ul> 

So now I'm trying to figure out how to do nesting using XSLT. This is what I have so far:

 <xsl:output method="xml" omit-xml-declaration="yes"/> <xsl:param name="currentPage"/> <!-- update this variable on how deep your menu should be --> <xsl:variable name="maxLevelForMenu" select="4"/> <xsl:template match="/"> <ul id="nav"> <xsl:call-template name="drawNodes"> <xsl:with-param name="parent" select="$currentPage/ancestor-or-self::node [@level=1]" /> </xsl:call-template> </ul> </xsl:template> <xsl:template name="drawNodes"> <xsl:param name="parent"/> <xsl:if test="umbraco.library:IsProtected($parent/@id, $parent/@path) = 0 or (umbraco.library:IsProtected($parent/@id, $parent/@path) = 1 and umbraco.library:IsLoggedOn() = 1)"> <xsl:for-each select="$parent/node [string(./data [@alias='umbracoNaviHide']) != '1' and @level &lt;= $maxLevelForMenu]"> <li> <a href="{umbraco.library:NiceUrl(@id)}"> <xsl:value-of select="@nodeName"/> </a> <xsl:if test="count(./node [string(./data [@alias='umbracoNaviHide']) != '1' and @level &lt;= $maxLevelForMenu]) &gt; 0"> <xsl:call-template name="drawNodes"> <xsl:with-param name="parent" select="."/> </xsl:call-template> </xsl:if> </li> </xsl:for-each> </xsl:if> </xsl:template> 

I cannot figure out how to check if the first level (here page # 1 and page # 2) has any children, and if they add an extra <ul> containing <li> children.

Can anyone point me in the right direction?

+4
source share
2 answers

First of all, you do not need to pass the parent parameter. The context will convey this information.

Here is the XSL stylesheet that should solve your problem:

 <!-- update this variable on how deep your menu should be --> <xsl:variable name="maxLevelForMenu" select="4"/> <!--- match the document root ---> <xsl:template match="/root"> <div id="nav"> <xsl:call-template name="SubTree" /> </div> </xsl:template> <!-- this will be called by xsl:apply-templates --> <xsl:template match="node"> <!-- the node is either protected, or the user is logged on (no need to check for IsProtected twice) --> <xsl:if test="umbraco.library:IsProtected($parent/@id, $parent/@path) = 0 or umbraco.library:IsLoggedOn() = 1"> <li> <a href="{umbraco.library:NiceUrl(@id)}"><xsl:value-of select="@nodeName"/></a> <xsl:call-template name="SubTree" /> </li> </xsl:if> </xsl:template> <xsl:template name="SubTree"> <!-- render sub-tree only if there are any child nodes ---> <xsl:if test="node"> <ul> <xsl:apply-templates select="node[data[@alias='umbracoNaviHide'] != '1'][@level &lt;= $maxLevelForMenu]"> <!-- ensure sorted output of the child nodes ---> <xsl:sort select="@sortOrder" data-type="number" /> </xsl:apply-templates> </ul> </xsl:if> </xsl:template> 

This is the XML on which I tested it (I know little about Umbraco, but looking at some samples, I hope I come closer to the Umbraco document):

 <root id="-1"> <node id="1" level="1" sortOrder="1" nodeName="Page #1"> <data alias="umbracoNaviHide">0</data> </node> <node id="2" level="1" sortOrder="2" nodeName="Page #2"> <data alias="umbracoNaviHide">0</data> <node id="3" level="2" sortOrder="2" nodeName="Subpage #2.2"> <data alias="umbracoNaviHide">0</data> </node> <node id="4" level="2" sortOrder="1" nodeName="Subpage #2.1"> <data alias="umbracoNaviHide">0</data> <node id="5" level="3" sortOrder="3" nodeName="Subpage #2.1.1"> <data alias="umbracoNaviHide">0</data> </node> </node> <node id="6" level="2" sortOrder="3" nodeName="Subpage #2.3"> <data alias="umbracoNaviHide">1</data> </node> </node> <node id="7" level="1" sortOrder="3" nodeName="Page #3"> <data alias="umbracoNaviHide">1</data> </node> </root> 

This is the conclusion:

 <div id="nav"> <ul> <li><a href="http://foo/">Page #1</a></li> <li><a href="http://foo/">Page #2</a> <ul> <li><a href="http://foo/">Subpage #2.1</a> <ul> <li><a href="http://foo/">Subpage #2.1.1</a></li> </ul> </li> <li><a href="http://foo/">Subpage #2.2</a></li> </ul> </li> </ul> </div> 
+5
source

There is nothing special about this problem. The following solution verifies that node-list for

  <xsl: apply-templates /> 

not empty before applying templates:

  <xsl: stylesheet version = "1.0"
  xmlns: xsl = "http://www.w3.org/1999/XSL/Transform">
  <xsl: output omit-xml-declaration = "yes" />
   <xsl: variable name = "vLevel" select = "0" />

     <xsl: template match = "root">
       <xsl: variable name = "vnextLevelNodes"
            select = "node [@level = $ vLevel + 1]" />
       <xsl: if test = "$ vnextLevelNodes">
        <ul>
          <xsl: apply-templates select = "$ vnextLevelNodes" />
        </ul>
       </ xsl: if>
     </ xsl: template>

     <xsl: template match = "node">
   <! - the node is either protected, or the user is logged on (no need to check for IsProtected twice) ->
     <! - <xsl: if test =
       "umbraco.library: IsProtected ($ parent / @ id, $ parent / @ path) = 0
       or
        umbraco.library: IsLoggedOn () = 1 "> ->
     <xsl: if test = "1">
         <li>
           <! - <a href = "{umbraco.library: NiceUrl (@id)}"> ->
           <a href="'umbraco.library:NiceUrl(@id)'">
             <xsl: value-of select = "@ nodeName" />
           </a>

                   <xsl: variable name = "vnextLevelNodes"
                        select = "node [@level = current () / @ level + 1]" />
                   <xsl: if test = "$ vnextLevelNodes">
                    <ul>
                      <xsl: apply-templates select = "$ vnextLevelNodes" />
                    </ul>
                   </ xsl: if>
         </li>
     </ xsl: if>
     </ xsl: template>
 </ xsl: stylesheet>

I used the following XML source document:

  <root id = "- 1">
     <node id = "1" level = "1" sortOrder = "1" nodeName = "Page # 1">
         <data alias = "umbracoNaviHide"> 0 </data>
     </node>
     <node id = "2" level = "1" sortOrder = "2" nodeName = "Page # 2">
         <data alias = "umbracoNaviHide"> 0 </data>
         <node id = "3" level = "2" sortOrder = "2" nodeName = "Subpage # 2.2">
             <data alias = "umbracoNaviHide"> 0 </data>
         </node>
         <node id = "4" level = "2" sortOrder = "1" nodeName = "Subpage # 2.1">
             <data alias = "umbracoNaviHide"> 0 </data>
             <node id = "5" level = "3" sortOrder = "3" nodeName = "Subpage # 2.1.1">
                 <data alias = "umbracoNaviHide"> 0 </data>
             </node>
         </node>
         <node id = "6" level = "2" sortOrder = "3" nodeName = "Subpage # 2.3">
             <data alias = "umbracoNaviHide"> 1 </data>
         </node>
     </node>
     <node id = "7" level = "1" sortOrder = "3" nodeName = "Page # 3">
         <data alias = "umbracoNaviHide"> 1 </data>
     </node>
 </root>

In addition, I commented on any code referencing the Umbraco extension functions, since I do not have access to them.

When the above conversion is applied to this source XML document, the correct, desired result is obtained:

  <ul>
     <li>
         <a href="'umbraco.library:NiceUrl(@id)'"> Page # 1 </a>
     </li>
     <li>
         <a href="'umbraco.library:NiceUrl(@id)'"> Page # 2 </a>
         <ul>
             <li>
                 <a href="'umbraco.library:NiceUrl(@id)'"> Subpage # 2.2 </a>
             </li>
             <li>
                 <a href="'umbraco.library:NiceUrl(@id)'"> Subpage # 2.1 </a>
                 <ul>
                     <li>
                         <a href="'umbraco.library:NiceUrl(@id)'"> Subpage # 2.1.1 </a>
                     </li>
                 </ul>
             </li>
             <li>
                 <a href="'umbraco.library:NiceUrl(@id)'"> Subpage # 2.3 </a>
             </li>
         </ul>
     </li>
     <li>
         <a href="'umbraco.library:NiceUrl(@id)'"> Page # 3 </a>
     </li>
 </ul>

Hope this helps.

Greetings

Dimitar Novachev

0
source

All Articles