Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Owen Hope 119 posts 140 karma points
    Nov 22, 2010 @ 20:00
    Owen Hope
    0

    Sub Navigation Problem

    Hello,

    Using Umbraco 4.5.2 and having some difficulties writing a XSLT for my Sub Navigation. 

    Here is my tree:

    Now I am a little unclear on levels, but my understanding is:

    Home - Level 1

    News and Media - Level 2

    Video - Level 3

    Campbell River Video - Level 4

     

    Now output is like this:

     

    So far I am able to output the Level 2 Nav ($currentPage name and id)

    But from there I am stumped. Here is my current XSLT:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp "&#x00A0;"> ]>
    <xsl:stylesheet
      version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:msxml="urn:schemas-microsoft-com:xslt"
      xmlns:umbraco.library="urn:umbraco.library" xmlns:Exslt.ExsltCommon="urn:Exslt.ExsltCommon" xmlns:Exslt.ExsltDatesAndTimes="urn:Exslt.ExsltDatesAndTimes" xmlns:Exslt.ExsltMath="urn:Exslt.ExsltMath" xmlns:Exslt.ExsltRegularExpressions="urn:Exslt.ExsltRegularExpressions" xmlns:Exslt.ExsltStrings="urn:Exslt.ExsltStrings" xmlns:Exslt.ExsltSets="urn:Exslt.ExsltSets" xmlns:tagsLib="urn:tagsLib" xmlns:BlogLibrary="urn:BlogLibrary"
      exclude-result-prefixes="msxml umbraco.library Exslt.ExsltCommon Exslt.ExsltDatesAndTimes Exslt.ExsltMath Exslt.ExsltRegularExpressions Exslt.ExsltStrings Exslt.ExsltSets tagsLib BlogLibrary ">


    <xsl:output method="xml" omit-xml-declaration="yes" />

    <xsl:param name="currentPage"/>

    <xsl:template match="/">
      <!-- Sub Nav Heading -->
      <h1>
        <a href="{umbraco.library:NiceUrl($currentPage/@id)}"><xsl:value-of select="$currentPage/@nodeName"/></a>
      </h1>
      
    <ul>
      <xsl:for-each select="$currentPage/ancestor-or-self::node [@level=2]/node [string(data [@alias='umbracoNaviHide']) != '1']">
        <xsl:if test="number($currentPage/@level)=3">
          <xsl:for-each select="$currentPage/child::node [@level=3]/node [string(data [@alias='umbracoNaviHide']) != '1']">
            <li>
              <a href="{umbraco.library:NiceURL($currentPage/@id)}"><xsl:value-of select="$currentPage/@nodeName"/></a>
            </li>
          </xsl:for-each>
        </xsl:if>
      </xsl:for-each>
    </ul>

    </xsl:template>

    </xsl:stylesheet>

     

    Any help or suggestions would be great! Still fairly new to XSLT.

    Thanks,

     

    Owen

  • Owen Hope 119 posts 140 karma points
    Nov 22, 2010 @ 21:10
    Owen Hope
    0

    Hi,

    I have managed to get the following output:

    using the following XSLT:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp "&#x00A0;"> ]>
    <xsl:stylesheet
      version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:msxml="urn:schemas-microsoft-com:xslt"
      xmlns:umbraco.library="urn:umbraco.library" xmlns:Exslt.ExsltCommon="urn:Exslt.ExsltCommon" xmlns:Exslt.ExsltDatesAndTimes="urn:Exslt.ExsltDatesAndTimes" xmlns:Exslt.ExsltMath="urn:Exslt.ExsltMath" xmlns:Exslt.ExsltRegularExpressions="urn:Exslt.ExsltRegularExpressions" xmlns:Exslt.ExsltStrings="urn:Exslt.ExsltStrings" xmlns:Exslt.ExsltSets="urn:Exslt.ExsltSets" xmlns:tagsLib="urn:tagsLib" xmlns:BlogLibrary="urn:BlogLibrary"
      exclude-result-prefixes="msxml umbraco.library Exslt.ExsltCommon Exslt.ExsltDatesAndTimes Exslt.ExsltMath Exslt.ExsltRegularExpressions Exslt.ExsltStrings Exslt.ExsltSets tagsLib BlogLibrary ">


    <xsl:output method="xml" omit-xml-declaration="yes" />

    <xsl:param name="currentPage"/>

    <xsl:template match="/">
      <!-- Sub Nav Heading -->
      <h1>
        <a href="{umbraco.library:NiceUrl($currentPage/@id)}"><xsl:value-of select="$currentPage/@nodeName"/></a>
      </h1>
     
    <xsl:if test="count($currentPage/* [@isDoc and string(umbracoNaviHide) != '1']) &gt; 0">
    <ul>
      <xsl:for-each select="$currentPage/* [@level=3 and @isDoc and string(data [@alias='umbracoNaviHide']) != '1']">
        <li>
          <a href="{umbraco.library:NiceUrl(@id)}"><xsl:value-of select="@nodeName"/></a>
          <xsl:if test="count($currentPage/*/* [@level=4 and @isDoc and string(umbracoNaviHide) != '1']) &gt; 0">
            <ul class="subnav">
              <xsl:for-each select="$currentPage/*/* [@level=4 and @isDoc and string(data [@alias='umbracoNaviHide']) != '1']">
              <li>
                <a href="{umbraco.library:NiceUrl(@id)}"><xsl:value-of select="@nodeName"/></a>
              </li>
              </xsl:for-each>
            </ul>
          </xsl:if
        </li>
      </xsl:for-each>
    </ul>
    </xsl:if>

    </xsl:template>

    </xsl:stylesheet>

     

    Now the problem is that the 4th tier child nodes are being printed for every 3rd child, instead of just only their parent. How can I constrain this?

     

    Thanks,


    Owen

  • Owen Hope 119 posts 140 karma points
    Nov 22, 2010 @ 22:14
    Owen Hope
    0

    Hi,

    Another update. I realized that I cannot base my navigation from the current page because if I navigate within my subnav the "current page" is no longer a level 2 node.

     

    So I have gone ahead and made the following changes:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp "&#x00A0;"> ]>
    <xsl:stylesheet
      version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:msxml="urn:schemas-microsoft-com:xslt"
      xmlns:umbraco.library="urn:umbraco.library" xmlns:Exslt.ExsltCommon="urn:Exslt.ExsltCommon" xmlns:Exslt.ExsltDatesAndTimes="urn:Exslt.ExsltDatesAndTimes" xmlns:Exslt.ExsltMath="urn:Exslt.ExsltMath" xmlns:Exslt.ExsltRegularExpressions="urn:Exslt.ExsltRegularExpressions" xmlns:Exslt.ExsltStrings="urn:Exslt.ExsltStrings" xmlns:Exslt.ExsltSets="urn:Exslt.ExsltSets" xmlns:tagsLib="urn:tagsLib" xmlns:BlogLibrary="urn:BlogLibrary"
      exclude-result-prefixes="msxml umbraco.library Exslt.ExsltCommon Exslt.ExsltDatesAndTimes Exslt.ExsltMath Exslt.ExsltRegularExpressions Exslt.ExsltStrings Exslt.ExsltSets tagsLib BlogLibrary ">


    <xsl:output method="xml" omit-xml-declaration="yes" />

    <xsl:param name="currentPage"/>

    <xsl:template match="/">
      <!-- Sub Nav Heading -->
      <h1>
        <a href="{umbraco.library:NiceUrl($currentPage/ancestor-or-self::*[@level = 2]/@id)}"><xsl:value-of select="$currentPage/ancestor-or-self::*[@level = 2]/@nodeName" /></a>
      </h1>
      
    <xsl:if test="count($currentPage/* [@isDoc and string(umbracoNaviHide) != '1']) &gt; 0">
    <ul>
      <xsl:for-each select="$currentPage/descendant-or-self::*[@level=3 and @isDoc and string(data [@alias='umbracoNaviHide']) != '1']">
        <li>
          <a href="{umbraco.library:NiceUrl(@id)}"><xsl:value-of select="@nodeName"/></a>
          <ul class="subnav">
            <xsl:for-each select="$currentPage/descendant-or-self::*[@level=4 and @isDoc and string(data [@alias='umbracoNaviHide']) != '1']">
              <li>
                <a href="{umbraco.library:NiceUrl(@id)}"><xsl:value-of select="@nodeName"/></a>
              </li>
            </xsl:for-each>
          </ul>
        </li>
      </xsl:for-each>
    </ul>
    </xsl:if>

    </xsl:template>

    </xsl:stylesheet>

     

    Now this gives me the Parent Node (level 2) and the Level 3 children of the Parent Node. However the level 4 children are listed underneath every Level 3 Node, instead of under their correct parent.

    Any help would be much appreciated.

     

    Owen

  • Owen Hope 119 posts 140 karma points
    Nov 23, 2010 @ 01:40
    Owen Hope
    0

    Hi,

    Still struggling with this, I am close as I am properly linking tier 2 and 3 nodes, just big problems on the tier 4. It seems that every tier 4 node found is being listed under all of the tier 3 node, instead of just the one its actually a child of.

    Heres a SS:

  • Chriztian Steinmeier 2800 posts 8790 karma points MVP 8x admin c-trib
    Nov 23, 2010 @ 02:07
    Chriztian Steinmeier
    0

    Hi Owen,

    Do you have a working HTML/CSS prototype of the navigation? Maybe we should have a look at that first and then decide how to best generate the desired output.

    Also: Take a look at my answer here: http://our.umbraco.org/forum/developers/xslt/14812-Navigation-help?p=0#comment54648 - that might actually be a good starting point...

    /Chriztian 

  • PRK 47 posts 119 karma points
    Nov 23, 2010 @ 11:27
    PRK
    0

    Hi Owen,

     

    check this code. You will have only to adjust for your needs. Hope it helps!

     

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE xsl:stylesheet [
        <!ENTITY nbsp "&#x00A0;">
    ]>
    <xsl:stylesheet
      version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:msxml="urn:schemas-microsoft-com:xslt"
      xmlns:umbraco.library="urn:umbraco.library"
      exclude-result-prefixes="msxml umbraco.library">
      
      <xsl:output method="xml" omit-xml-declaration="yes"/>
      <xsl:param name="currentPage"/>
      
      <xsl:template match="/">
      
        <!-- Root Node -->
        <xsl:variable name="rootNode" select="$currentPage/ancestor-or-self::root" />

        <!-- Homepage -->
        <xsl:variable name="homeNode" select="$rootNode/Home [@isDoc]" />
        
        <ul>
          <li>
            <xsl:if test="$homeNode/@id = $currentPage/@id">
              <xsl:attribute name="class">
                <xsl:text>visited</xsl:text>
              </xsl:attribute>
            </xsl:if>
            
            <a href="{umbraco.library:NiceUrl($homeNode/@id)}">
              <xsl:value-of select="$homeNode/@nodeName" />
            </a>
          </li>
          
          <xsl:for-each select="$homeNode/* [@isDoc and @level = 2 and string(umbracoNaviHide) != '1']">
            <li>
              <xsl:if test="$currentPage/ancestor-or-self::* [@isDoc]/@id = current()/@id">
                <xsl:attribute name="class">
                  <xsl:text>visited</xsl:text>
                </xsl:attribute>
              </xsl:if>
              
              <a href="{umbraco.library:NiceUrl(@id)}">
                <xsl:value-of select="@nodeName" />
              </a>
              
              <xsl:variable name="subItems" select="umbraco.library:GetXmlNodeById(@id)/child::* [@isDoc][string(umbracoNaviHide) != '1']"/>
                <xsl:if test="count($subItems)">
                  <table><tr><td>
                    <ul>
                      <xsl:for-each select="$subItems">
                        <li>
                          <a href="{umbraco.library:NiceUrl(@id)}">
                            <xsl:value-of select="@nodeName"/>
                          </a>
                        </li>
                      </xsl:for-each>
                   </ul>
                  </td></tr></table>
                </xsl:if>
              
              <xsl:variable name="subsubItems" select="$subItems/descendant-or-self::* [@isDoc and @level = 4 and string(umbracoNaviHide) != '1']"/>
                <xsl:if test="count($subsubItems)">
                  <table><tr><td>
                    <ul>
                      <xsl:for-each select="$subsubItems">
                        <li>
                          <a href="{umbraco.library:NiceUrl(@id)}">
                            <xsl:value-of select="@nodeName"/>
                          </a>
                        </li>
                      </xsl:for-each>
                   </ul>
                  </td></tr></table>
                </xsl:if>
              
            </li>
          </xsl:for-each>
        </ul>
      </xsl:template>
    </xsl:stylesheet>

    /PRK

  • Owen Hope 119 posts 140 karma points
    Nov 23, 2010 @ 18:17
    Owen Hope
    0

    Hello,

    Thank you for your comments, I have been playing around with my XSLT a little more and I feel that I am very close to getting the desired solution.

    I have omitted some of the generic code but my latest XSLT looks like this:

    <xsl:param name="currentPage"/>
        
        <xsl:variable name="parentNode" select="$currentPage/ancestor-or-self::*[@level = 2]"/>

    <xsl:template match="/">
      <!-- Sub Nav Heading -->
      <h1>
        <a href="{umbraco.library:NiceUrl($parentNode/ancestor-or-self::*[@level = 2]/@id)}"><xsl:value-of select="$parentNode/ancestor-or-self::*[@level = 2]/@nodeName" /></a>
      </h1>
      
    <xsl:if test="count($parentNode/* [@isDoc and string(umbracoNaviHide) != '1']) &gt; 0">
    <ul>
      <xsl:for-each select="$parentNode/descendant-or-self::*[@level=3 and @isDoc and string(data [@alias='umbracoNaviHide']) != '1']">
        <li>
          <a href="{umbraco.library:NiceUrl(@id)}"><xsl:value-of select="@nodeName"/></a>
           <ul class="subnav"> //THIS IS WHERE THE PROBLEM LIES
            <xsl:for-each select="$parentNode/descendant::*[@level=4 and @isDoc and string(data [@alias='umbracoNaviHide']) != '1']">
                  <li>
                    <a href="{umbraco.library:NiceUrl(@id)}"><xsl:value-of select="@nodeName"/></a>
                  </li>
            </xsl:for-each>
          </ul>
        </li>
      </xsl:for-each>
    </ul>
    </xsl:if>

    </xsl:template>

    </xsl:stylesheet>

     

    From my structure below you can see that the "Videos" section has two children "Campbell River Video" and "Test Video sub Page"

    These should be only listed under the Videos section, but instead is being listed under all Level 3 nodes. I need a way of enforcing that the nodes only be printed under their parent.

     

    Thanks for the help, hopefully this will lead to a more clear understanding.

     

    Owen

     

    PS: Yes, I have wrote this sub-nav in ASP.NET and had it working, however I would like to use XSLT as its a little tidier and generally there is more support for it here on the forums!

  • Owen Hope 119 posts 140 karma points
    Nov 23, 2010 @ 21:16
    Owen Hope
    0

    Still stumped, and I've tried a lot of different approaches and read a lot of forums.

    No one has ever dealt with something like this before?

    Owen

  • Jan Skovgaard 11280 posts 23678 karma points MVP 11x admin c-trib
    Nov 23, 2010 @ 21:52
    Jan Skovgaard
    0

    Hi Owen

    Have you had a look at the link Chriztian posted earlier? It's really not more advanced thant that. If it's getting the "Home" node that's causing the problem, then hardcode it into the file.

    I really urge you to take a look at Chriztians sample. That's a good way to achieve your goal I think.

    /Jan

  • rorythecheese 110 posts 56 karma points
    Nov 23, 2010 @ 23:54
    rorythecheese
    1

    This should work i think. The problem was that the 2nd loop wasn't being related to the 1st loop because you were using the $parentNode variable which was pulling it out of the loop and starting again. If you're in a loop then the nestedloop only needs to be relative to the outerloop. So if you're in the level 3 loop then you can be safe to assume that the next level down is 4 so you can just use the *[@isDoc] to loop the next level.

    Haven't tested it though so could be an error or something in there.

    <xsl:variable name="parentNode" select="$currentPage/ancestor-or-self::*[@isDoc and @level = 2]"/>
    
    <xsl:template match="/">
        <!-- Level 2 -->
        <h1>
            <a href="{umbraco.library:NiceUrl($parentNode/@id)}">
                <xsl:value-of select="$parentNode/@nodeName"/>
            </a>
        </h1>
    
        <!--Level 3-->
        <xsl:if test="count($parentNode/*[@isDoc and string(umbracoNaviHide)!='1']) &gt; 0">
            <ul>
                <xsl:for-each select="$parentNode/*[@isDoc and string(umbracoNaviHide)!='1']">
                    <li>
                        <a href="{umbraco.library:NiceUrl(@id)}">
                            <xsl:value-of select="@nodeName"/>
                        </a>
    
                        <!--Level 4-->
                        <xsl:if test="count(*[@isDoc and string(umbracoNaviHide)!='1']) &gt; 0">
                            <ul class="subnav">
                                <xsl:for-each select="*[@isDoc and string(umbracoNaviHide)!='1']">
                                    <li>
                                        <a href="{umbraco.library:NiceUrl(@id)}">
                                            <xsl:value-of select="@nodeName"/>
                                        </a>
                                    </li>
                                </xsl:for-each>
                            </ul>
                        </xsl:if>
                    </li>
                </xsl:for-each>
            </ul>
        </xsl:if>
    
    </xsl:template>
  • Owen Hope 119 posts 140 karma points
    Nov 24, 2010 @ 00:35
    Owen Hope
    0

    Rory!

    You are my savior! Thank you so much, I completely understand now!

    Thanks again!


    Owen +1

Please Sign in or register to post replies

Write your reply to:

Draft