Copied to clipboard

Flag this post as spam?

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


  • Dan 1288 posts 3921 karma points c-trib
    Mar 22, 2010 @ 12:00
    Dan
    0

    Nested list

    Hi,

    I'm trying to output the next two levels of navigation from a particular node.  I can get the XSLT to output a list of the correct items, but I can't seem to get it to nest the list.  i.e. I want it to output:

    <ul id="subnav">
    <li>
    <a href="">2010</a>
    <ul>
    <li><a href="">January</a></li>
    <li><a href="">February</a></li>
    <li><a href="">March</a></li>
    </ul>
    </li>
    <li>
    <a href="">2009</a>
    <ul>
    <li><a href="">January</a></li>
    <li><a href="">February</a></li>
    <li><a href="">March</a></li>
    </ul>
    </li>
    </ul>

    But it just outputs:

    <ul>
    <li><a href="">2010</a></li>
    <li><a href="">January</a></li>
    <li><a href="">February</a></li>
    <li><a href="">March</a></li>
    <li><a href="">2009</a></li>
    <li><a href="">January</a></li>
    <li><a href="">February</a></li>
    <li><a href="">March</a></li>
    </ul>

    The code I'm using is this:

    <xsl:variable name="source" select="/macro/source"/>
    <xsl:variable name="maxLevelForNav" select="4"/>

    <xsl:template match="/">

    <ul id="subnav">
    <xsl:for-each select="umbraco.library:GetXmlNodeById($source)/descendant::node [string(data [@alias='umbracoNaviHide']) != '1' and @level &lt;= $maxLevelForNav]">
    <li>
    <a href="{umbraco.library:NiceUrl(@id)}">
    <xsl:value-of select="@nodeName"/>
    </a>
    </li>
    </xsl:for-each>
    </ul>

    </xsl:template>

     

    Can anyone see how I can do this?

    Thanks all...

  • Lee Kelleher 4026 posts 15836 karma points MVP 13x admin c-trib
    Mar 22, 2010 @ 12:22
    Lee Kelleher
    0

    Hi Dan,

    Your initial for-each select is calling all the descendant nodes, where it should be using just the first level, and then within the for-each, you can check if it has any child nodes - and loop accordingly.

    <xsl:variable name="source" select="/macro/source"/>
    
    <xsl:template match="/">
        <ul id="subnav">
            <xsl:for-each select="umbraco.library:GetXmlNodeById($source)/node[string(data[@alias='umbracoNaviHide']) != '1']">
                <li>
                    <a href="{umbraco.library:NiceUrl(@id)}">
                        <xsl:value-of select="@nodeName"/>
                    </a>
                    <xsl:if test="count(node[string(data[@alias='umbracoNaviHide']) != '1']) &gt; 0">
                        <xsl:for-each select="node[string(data[@alias='umbracoNaviHide']) != '1']">
                            <li>
                                <a href="{umbraco.library:NiceUrl(@id)}">
                                    <xsl:value-of select="@nodeName"/>
                                </a>
                            </li>
                        </xsl:for-each>
                    </xsl:if>
                </li>
            </xsl:for-each>
        </ul>
    </xsl:template>

    I've removed the "maxLevelForNav" variable ... I didn't see a need for it. :-)

    Cheers, Lee.

  • Lee Kelleher 4026 posts 15836 karma points MVP 13x admin c-trib
    Mar 22, 2010 @ 12:23
    Lee Kelleher
    0

    oops, missed a bit.  Between the nested IF and FOR-EACH, put the <ul> tags.

  • dandrayne 1138 posts 2262 karma points
    Mar 22, 2010 @ 12:24
    dandrayne
    3

    You'll probably find it useful to use a recursive template for this.  For a good example create a new xslt file and choose "sitemap" from the list of predefined templates.

    In particular look at the drawNodes template, which operates as follows

    • This template draws out the child nodes of the parent node (which is passed in as paramater 'parent')
    • For each node encountered, the template checks to see if it has any child nodes
    • If it does, it calls itself but using the current node as the parent
    • rinse and repeat, up until it reaches a level that matches the stated max level

    Hope this helps - best bet is to dissect the existing xslt for this, it's the best way to learn!

    Dan

     

  • Dan 1288 posts 3921 karma points c-trib
    Mar 22, 2010 @ 12:42
    Dan
    0

    Thanks Lee - that worked perfectly.

    Dan, I did want to use recursive templates for this as it seems like the next gap up in my XLST understanding and I can see how it would make the solution above a bit neater.  I tried to modify the 'list whole structure from current page' template initially, but couldn't get it to work quite right.  I'll look into this though as it would help understand a lot of the XSLT structures in the packages I use (e.g. XSLT search etc).  Back to W3Schools as soon as I get chance :)

  • Lee Kelleher 4026 posts 15836 karma points MVP 13x admin c-trib
    Mar 22, 2010 @ 13:20
    Lee Kelleher
    1

    Hi Dan,

    Following on from Dan (Drayne)'s suggestion, here's a quick example of how to use recursive templates.  Using apply-templates over for-each is nicer to the XSLT processor, (or so I am lead to believe).

    <xsl:variable name="source" select="/macro/source"/>
    
    <xsl:template match="/">
        <xsl:variable name="root" select="umbraco.library:GetXmlNodeById($source)" />
        <xsl:if test="count($root) &gt; 0">
            <xsl:variable name="nodes" select="$root/node[string(data[@alias='umbracoNaviHide']) != '1']" />
            <xsl:if test="count($nodes) &gt; 0">
                <ul id="subnav">
                    <xsl:apply-templates select="$nodes" />
                </ul>
            </xsl:if>
        </xsl:if>
    </xsl:template>
    
    <xsl:template match="node">
        <xsl:variable name="nodes" select="node[string(data[@alias='umbracoNaviHide']) != '1']" />
        <li>
            <a href="{umbraco.library:NiceUrl(@id)}">
                <xsl:value-of select="@nodeName" />
            </a>
            <xsl:if test="count($nodes) &gt; 0">
                <ul>
                    <xsl:apply-templates select="$nodes" />
                </ul>
            </xsl:if>
        </li>
    </xsl:template>

    If you follow down the logic of first template (match="/") ... it reaches the apply-templates, then goes to the template (match="node" ... because the XML element is called "node" and it matches it; obvious, I know!)  Then inside the IF condition, the template is applied again.

    Any questions, let us know!

    Cheers, Lee.

    PS. Where about in Bristol are you? You should come along to the next Umbraco Bristol (South West) meet-up? (twitter / contact me)

  • Dan 1288 posts 3921 karma points c-trib
    Mar 22, 2010 @ 14:53
    Dan
    0

    Cheers Lee, that's really really helpful.

    I'm based near Bristol harbour - in a studio very close to the SS Great Britain.  I'd definitely be up for attending the next south-west meet-up.  I know you guys have met up a couple of times recently, but I've just become a dad for the second time so things are a bit hectic at the moment and I'm not getting much time for 'extra-curricular' stuff :)

    I'm trying to get a couple of other Bristol studios to start working with Umbraco, so I'll link them in too if they do.  It would be good to build the SW community a little and have some more local companies on board.

  • Lee Kelleher 4026 posts 15836 karma points MVP 13x admin c-trib
    Mar 22, 2010 @ 15:13
    Lee Kelleher
    0

    Hi Dan, I know how it is... got a 2yo girl here! Fun & joys of fatherhood!

    We're planning on making the Bristol meet-up bi-monthly (or whatever the word is for once every two months?), so next will be around mid-May. (No exact dates planned, so feel free to suggest a date that suits you?)

Please Sign in or register to post replies

Write your reply to:

Draft