Copied to clipboard

Flag this post as spam?

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


  • Graham Mulcock 26 posts 48 karma points
    May 12, 2010 @ 18:57
    Graham Mulcock
    0

    Staring at XSLT - no result...

    Trying to understand why this XSLT is not working for me, and wondering if someone can help. On each of my pages, I have a custom property with alias of 'menuText', intended to allow the name of a menu item to be different from the nodeName. Currently, I have 3 pages at the same level which can populate a menu, therefore I would expect to see 3 items in the menu. The problem is this: while I do indeed see 3 items in the menu, the menuText for the first item in the menu is applied to all menu items. However, the link URLs in each case are correct.

    <?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 omit-xml-declaration="yes" indent="yes" encoding="utf-8"/>
    <xsl:param name="currentPage"/>
    <xsl:template match="/">
     <xsl:variable name="pageId" select="$currentPage/@id"/>
     <xsl:variable name="parentElement" select="$currentPage/ancestor-or-self::node[@level=2]"/>
     <!--<h2><xsl:value-of select="$parentElement/@nodeName"/></h2>-->
     <ul>
     <xsl:for-each select="$parentElement//descendant::node[@level=3] [string(data[@alias='umbracoNaviHide']) != '1']">
      <xsl:sort select="@nodeName" data-type="text" order="ascending" />
      <li>
      <a href="{umbraco.library:NiceUrl(@id)}">
       <xsl:value-of select="$parentElement/descendant::node/data[@alias='menuText']"/>
      </a>
      <xsl:call-template name="RenderSubItems">
       <xsl:with-param name="parent" select="."/>
      </xsl:call-template>
      </li>
     </xsl:for-each>
     </ul>
    </xsl:template>
    <xsl:template name="RenderSubItems">
     <xsl:param name="parent"/>
     <xsl:if test="count($parent/descendant::node [string(data[@alias='umbracoNaviHide']) != '1']) &gt; 0">
      <ul>
      <xsl:for-each select="$parent/descendant::node [string(data[@alias='umbracoNaviHide']) != '1']">
       <li>
       <a href="{umbraco.library:NiceUrl(@id)}">
        <xsl:value-of select="$parent/descendant::node/data[@alias='menuText']"/>
       </a>
       </li>
      </xsl:for-each>
      </ul>
     </xsl:if>
    </xsl:template>
    </xsl:stylesheet>

    Thanks to anyone who can assist. I'm new to Umbraco, and although I understand its features, I'm finding it a bit of a pig to work with....

     

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

    Hi Graham, welcome to the Umbraco community forum!

    OK, the problem is with the reference to the node (that has the 'menuText' data), instead of this:

    <xsl:value-of select="$parentElement/descendant::node/data[@alias='menuText']"/>

    try removing the "$parentElement" stuff, so it's like this:

    <xsl:value-of select="data[@alias='menuText']"/>

    I know how frustrating XSLT/XPath can be... let us know how you get on!

    Good luck, Lee.

  • Tom Fulton 2030 posts 4998 karma points c-trib
    May 12, 2010 @ 19:05
    Tom Fulton
    1

    Hi,

    At first glance, it looks like the problem is you are always referring to the same node to get the menuText -    <xsl:value-of select="$parentElement/descendant::node/data[@alias='menuText']"/>

    This should be changed to

       <xsl:value-of select="./data[@alias='menuText']"/>

    The '.' or 'current()' will give you the current item in the for loop, which sounds like what you want.

    Thanks,

    Tom

  • Graham Mulcock 26 posts 48 karma points
    May 12, 2010 @ 19:09
    Graham Mulcock
    0

    Brilliant! That worked a treat. Thanks very much guys for a quick reply. Issue closed...

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

    Hi Graham, don't forget to mark the solution. :-)  Thanks, Lee.

  • Graham Mulcock 26 posts 48 karma points
    May 13, 2010 @ 15:42
    Graham Mulcock
    0

    Not done yet.... Below is how the XSLT looks now. But, having added sub-level pages, they are not appearing in the menu as dropdowns (via RenderSubItems). I'm seeing a Javascript editor in the preview 'parent().get(...) is null or not an object'.

    <?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 omit-xml-declaration="yes" indent="yes" encoding="utf-8"/>
    <xsl:param name="currentPage"/>
    <xsl:template match="/">
     <xsl:variable name="pageId" select="$currentPage/@id"/>
     <xsl:variable name="parentElement" select="$currentPage/ancestor-or-self::node[@level=2]"/>
     <ul>
     <xsl:for-each select="$parentElement//descendant::node[@level=3] [string(data[@alias='umbracoNaviHide']) != '1']">
      <xsl:sort select="@nodeName" data-type="text" order="ascending" />
      <li>
      <a href="{umbraco.library:NiceUrl(@id)}">
       <xsl:value-of select="./data[@alias='menuText']"/>
      </a>
      <xsl:call-template name="RenderSubItems">
       <xsl:with-param name="parent" select="."/>
      </xsl:call-template>
      </li>
     </xsl:for-each>
     </ul>
    </xsl:template>
    <xsl:template name="RenderSubItems">
     <xsl:param name="parent"/>
     <xsl:if test="count($parent/descendant::node [string(data[@alias='umbracoNaviHide']) != '1']) &gt; 0">
      <ul>
      <xsl:for-each select="$parent/descendant::node [string(data[@alias='umbracoNaviHide']) != '1']">
       <xsl:sort select="@nodeName" data-type="text" order="ascending" />
       <li>
       <a href="{umbraco.library:NiceUrl(@id)}">
        <xsl:value-of select="./data[@alias='menuText']"/>
       </a>
       </li>
      </xsl:for-each>
      </ul>
     </xsl:if>
    </xsl:template>
    </xsl:stylesheet>

    I feel such an idiot not getting this - I've used XSLT/XPATH in other apps for a long time, but in a different environment. Frustrating.

  • Lee Kelleher 4026 posts 15836 karma points MVP 13x admin c-trib
    May 13, 2010 @ 16:43
    Lee Kelleher
    0

    Hi Graham,

    If I can be honest with you for a moment, the use of variables and XPath axes (ancestor / descendant) is way too confusing in your XSLT! Things can be much much simpler.  Let me show you how.

    <?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 encoding="utf-8" indent="yes" method="xml" omit-xml-declaration="yes" />
    
        <xsl:param name="currentPage"/>
    
        <xsl:template match="/">
            <!-- set the variable with the parent node @level=2 -->
            <xsl:variable name="parentNode" select="$currentPage/ancestor-or-self::node[@level=2]" />
            <ul>
                <!-- apply the templates to loop through each of the child nodes (that are not hidden from nav) -->
                <xsl:apply-templates select="$parentNode/node[string(data[@alias='umbracoNaviHide']) != '1']">
                    <xsl:sort select="@nodeName" data-type="text" order="ascending" />
                </xsl:apply-templates>
            </ul>
        </xsl:template>
    
        <xsl:template match="node">
            <li>
                <a href="{umbraco.library:NiceUrl(@id)}">
                    <!-- check if the node has the 'menuText' set, otherwise fallback on the 'nodeName' -->
                    <xsl:choose>
                        <xsl:when test="string-length(data[@alias='menuText']) &gt; 0">
                            <xsl:value-of select="data[@alias='menuText']" />
                        </xsl:when>
                        <xsl:otherwise>
                            <xsl:value-of select="@nodeName" />
                        </xsl:otherwise>
                    </xsl:choose>
                </a>
    
                <!-- check if the node has any children (that are not hidden from nav) -->
                <xsl:if test="count(node[string(data[@alias='umbracoNaviHide']) != '1']) &gt; 0">
                    <ul>
                        <!-- apply the templates for the sub-child nodes -->
                        <xsl:apply-templates select="node[string(data[@alias='umbracoNaviHide']) != '1']">
                            <xsl:sort select="@nodeName" data-type="text" order="ascending" />
                        </xsl:apply-templates>
                    </ul>
                </xsl:if>
    
            </li>
        </xsl:template>
    
    </xsl:stylesheet>

    OK, in this XSLT we have 2 templates, the main one and another for <node> elements.  For the main template I've kept the 'parentNode' variable, it's not really needed, but it's there just in case you need to do anything else with it.  We then apply-templates against all the child <node> elements (that aren't hidden using 'umbracoNaviHide'...

    For each <node> element that is matched, the template is applied... then within that we apply the template recursively to all/any child sub-pages.

    Hope this makes sense?  It should cut-down the amount of HTML you need to maintain too?

    Let us know how it goes.

    Cheers, Lee.

  • Graham Mulcock 26 posts 48 karma points
    May 13, 2010 @ 17:22
    Graham Mulcock
    0

    Lee, you're very kind to provide that sample and thank you. I understand how it works, and indeed it is simpler. However, I'm still not seeing the lower-level items, which are programmed to be visible. The Javascript error appears to be generated within the Dynamic Drive ddmenu.js. This works fine in my pure HTML version of the site I'm migrating, but not here. Maybe DD is not the way to go in this case... Aaagh! Is there an easier multi-level menu generator to use...?

     

  • Graham Mulcock 26 posts 48 karma points
    May 13, 2010 @ 18:30
    Graham Mulcock
    1

    OK, fixed it now. It was an incorrect ID on the menu <div>. Sorry for the confusion and many thanks again for your help. Now moving on to look at forms >> database. Oh, joy....

  • Lee Kelleher 4026 posts 15836 karma points MVP 13x admin c-trib
    May 13, 2010 @ 20:21
    Lee Kelleher
    0

    No worries Graham, glad that you've got it working now.

    Good luck with the rest of your site/project.

    Cheers, Lee.

Please Sign in or register to post replies

Write your reply to:

Draft