Copied to clipboard

Flag this post as spam?

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


  • mmaty 113 posts 286 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 113 posts 286 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 2800 posts 8790 karma points MVP 8x 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

Please Sign in or register to post replies

Write your reply to:

Draft