Copied to clipboard

Flag this post as spam?

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


  • mmaty 87 posts 216 karma points
    Nov 15, 2011 @ 00:21
    mmaty
    0

    Try to understand the navigation xslt

    Hi all,

    I'm evaluating umbraco and can't find out, how to get a multi-level menu.

    I hope, somebody can explain, how the menu navigation code works.

    As far as I understand the system, the xslt transforms the contents of the umbraco.config file, which is located in App_Data. In order to test my xslt code in Visual Studio I change two lines of the xslt code, so that currentPage is not a param, but a variable and the umbraco.library:NiceUrl is not used.

    My xslt looks like that:

    <?xml version="1.0" encoding="UTF-8"?>
    <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:variable name="currentPage" select="/root/umbTextpage[1]"/>
      <xsl:template match="/">
        <xsl:call-template name="makeNode">
          <xsl:with-param name="parent" select="/root" />
        </xsl:call-template>
      </xsl:template>
      <xsl:template name ="makeNode" >
        <xsl:param name="parent" />
        <ul>
            <xsl:for-each select="$parent/*[@nodeName]">
            <li>
              <xsl:if test="@id = $currentPage/@id">
                <xsl:attribute name="class">current</xsl:attribute>
              </xsl:if>
              <!--a href="{umbraco.library:NiceUrl(@id)}"-->
                <a href="@id">
                  <xsl:value-of select="@nodeName"/>
              </a>
              <xsl:if test="count(./*[@nodeName]) > 0">
                <xsl:call-template name="makeNode">
                  <xsl:with-param name="parent" select="." />
                </xsl:call-template>
              </xsl:if>
            </li>
          </xsl:for-each>
        </ul>
      </xsl:template>
    </xsl:stylesheet> 

     My umbraco.config looks like that:

    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE root[
    <!ELEMENT umbTextpage ANY>
    <!ATTLIST umbTextpage id ID #REQUIRED>
    ]>
    <root id="-1">
      <umbTextpage id="1093" parentID="-1" level="1" writerID="0" creatorID="0" nodeType="1060" template="1092" sortOrder="2" createDate="2011-11-14T19:04:57" updateDate="2011-11-14T22:40:29" nodeName="Home" urlName="home" writerName="admin" creatorName="admin" path="-1,1093" isDoc="">
        <bodyText>
          <![CDATA[
    <h2>Willkommen auf meiner Website</h2>
    ]]>
        </bodyText>
        <title>Home</title>
      </umbTextpage>
      <umbTextpage id="1094" parentID="-1" level="1" writerID="0" creatorID="0" nodeType="1060" template="1092" sortOrder="55" createDate="2011-11-14T20:11:24" updateDate="2011-11-14T22:47:55" nodeName="Das Buch" urlName="das-buch" writerName="admin" creatorName="admin" path="-1,1094" isDoc="">
        <bodyText>
          <![CDATA[
    <p><img src="/images/buch.jpg" alt="Das Buch"/></p>
    <p>Hallo!!!!</p>
    ]]>
        </bodyText>
        <title>Das Buch</title>
        <umbTextpage id="1095" parentID="-1" level="2" writerID="0" creatorID="0" nodeType="1060" template="1092" sortOrder="56" createDate="2011-11-14T20:12:07" updateDate="2011-11-14T22:48:20" nodeName="Subpage" urlName="subpage" writerName="admin" creatorName="admin" path="-1,1095" isDoc="">
          <bodyText>
            <![CDATA[
    <h1>Subpage</h1>
    <p>Text</p>
    ]]>
          </bodyText>
          <title>Subpage</title>
        </umbTextpage>
      </umbTextpage>
    </root>

    So the structure is:

    Home
    Das Buch
        Subpage

    Applying the given xslt to the umbraco.config gives me the wished result:

    <ul>
      <li class="current">
        <a href="@id">Home</a>
      </li>
      <li>
        <a href="@id">Das Buch</a>
        <ul>
          <li>
            <a href="@id">Subpage</a>
          </li>
        </ul>
      </li>
    </ul>

     Now I change the two lines to let the xslt work in umbraco. I change

    <xsl:variable name="currentPage" select="/root/umbTextpage[1]"/>

     to

    <xsl:param name="currentPage" />

     and

     

     

    <a href="@id">

     

     

     to

    <a href="{umbraco.library:NiceUrl(@id)}">

     Starting the page with umbraco, gives me the following result:

    <ul />

    It seems, that I didn't understand, how the xslt in umbraco works. Most umbraco examples I found by google use an xpath like

    <xsl:for-each select="$currentPage/ancestor-or-self::* [@level=$nodeLevel]/* [@isDoc and string(umbracoNaviHide) != '1']">

    but this gives me no resuts. 

    <xsl:for-each select="$currentPage/ancestor-or-self::* [@level=$nodeLevel]">

    delivers the Home page link only.

    Could somebody explain, how the xslt works?

    Best regards
    mmaty

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    <?xml version="1.0" encoding="UTF-8"?>
    <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" select="/root/umbTextpage[1]"/>
    <!-- replacing the xsl:param with xsl:variable lets me test the code -->

      <xsl:template match="/">
        <xsl:call-template name="makeNode">
          <xsl:with-param name="nodeLevel">1</xsl:with-param>
        </xsl:call-template>
      </xsl:template>

      <xsl:template name ="makeNode" >
        <xsl:param name="nodeLevel" />
        <ul>
            <xsl:for-each select="/root/descendant::* [@level=$nodeLevel]">
            <li>
              <xsl:if test="@id = $currentPage/@id">
                <xsl:attribute name="class">current</xsl:attribute>
              </xsl:if>
              <!--a href="{umbraco.library:NiceUrl(@id)}" masked out for testing -->
                <a href="@id">
                  <xsl:value-of select="@nodeName"/>
              </a>
              <xsl:variable name ="newLevel" select="$nodeLevel + 1" />
              <xsl:if test="count(/root/descendant::* [@level=$newLevel]) > 0">
                <xsl:call-template name="makeNode">
                <xsl:with-param name="nodeLevel" select="$newLevel" />
              </xsl:call-template>
              </xsl:if>
            </li>
          </xsl:for-each>
        </ul>
      </xsl:template>


      <!-- Never output these -->
      <xsl:template match="*[umbracoNaviHide = 1]" />
    </xsl:stylesheet>

     

  • mmaty 87 posts 216 karma points
    Nov 15, 2011 @ 10:55
    mmaty
    0

    OK, I got it. The solution is umbraco.library.GetXmlAll(). This returns the cached xml, as it appears in the App_Data/umbraco.config. GetXmlAll() delivers directly the root node.

    The complete and working code for a recursive menu is the following:

    <?xml version="1.0" encoding="UTF-8"?>
    <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" />
    <!--select="/root/umbTextpage[1]"-->
      <xsl:param name="currentPage"/>
      <xsl:template match="/">
        <xsl:call-template name="makeNode">
          <xsl:with-param name="parent" select="umbraco.library:GetXmlAll()" />
        </xsl:call-template>
      </xsl:template>
      <xsl:template name ="makeNode" >
        <xsl:param name="parent" />
        <ul>
            <xsl:for-each select="$parent/*[@nodeName]">
            <li>
              <xsl:if test="@id = $currentPage/@id">
                <xsl:attribute name="class">current</xsl:attribute>
              </xsl:if>
              <a href="{umbraco.library:NiceUrl(@id)}">
                  <xsl:value-of select="@nodeName"/>
              </a>
              <xsl:if test="count(./*[@nodeName]) > 0">
                <xsl:call-template name="makeNode">
                  <xsl:with-param name="parent" select="." />
                </xsl:call-template>
              </xsl:if>
            </li>
          </xsl:for-each>
        </ul>
      </xsl:template>
    </xsl:stylesheet>

    BTW, the HTML editor in your forum is simply not working. I tried to remove the code block at the end of my last post, but the editor window is completely confused, if I press the edit button. Some code disappears partly.

    In this reply window I can't choose the code paragraph format....

    Regards
    mmaty

     

  • Chriztian Steinmeier 2726 posts 8320 karma points MVP 4x admin c-trib
    Nov 15, 2011 @ 11:23
    Chriztian Steinmeier
    1

    Hi mmaty,

    Actually, a better solution would be to set a variable after the currentPage param:

    <xsl:param name="currentPage" />
    <xsl:variable name="absoluteRoot" select="$currentPage/ancestor-or-self::root" />

    - and then use $absoluteRoot instead of GetXmlAll().

    The problem is that in the root template (match="/"), the / refers to a simple <macro> element that Umbraco uses to run the transformation. So we need to use $currentPage to connect to the Umbraco XML document, and we already have that available, so no need to call an extension function.

    /Chriztian

  • This forum is in read-only mode while we transition to the new forum.

    You can continue this topic on the new forum by tapping the "Continue discussion" link below.

Please Sign in or register to post replies