Copied to clipboard

Flag this post as spam?

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


  • Ferdy Hoefakker 214 posts 248 karma points
    Mar 06, 2013 @ 15:42
    Ferdy Hoefakker
    0

    XSLT performance bottleneck

    Hello,

    One of our sites is experiences performance issues. Using the umbDebugShowTrace I have narrowed it down to a specific XSLT file. Now, I have checked it over, and the only parts that (to me anyway) seem like they could be the cause are the for-each loops we use. I have however, no idea of how to get the data I need with another (more optimized) Xpath expression. If someone could take a look at this that'd be great.

    -Ferdy

    The 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"
      exclude-result-prefixes="msxml umbraco.library">


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

    <xsl:param name="currentPage"/>  
        
    <xsl:template match="/">
      <ul id="nav">
          
        <xsl:for-each select="$currentPage/ancestor-or-self::*[@isDoc]/descendant-or-self::*[@isDoc] [umbraco.library:HasAccess(@id,@path)  and string(naviHide) != '1' and (self::Nieuws or self::Pagina) and @level &gt; 0]">
          <xsl:sort select="@sortOrder" data-type="number" order="ascending" />
          <xsl:variable name="menuName" select="menuName"/>
          <li>
            <xsl:if test="contains(@nodeName, 'commerce')">
              <xsl:attribute name="class">menuHeaderCommerce</xsl:attribute>
            </xsl:if>
            <xsl:if test="contains(@nodeName, 'Meldpunt') or contains(@nodeName, 'point de')">
              <xsl:attribute name="class">menuHeaderMeldpunt</xsl:attribute>
            </xsl:if>
            <xsl:if test="contains(@nodeName, 'corporate')">
              <xsl:attribute name="class">menuHeaderCorporate</xsl:attribute>
            </xsl:if>
            <a href="{umbraco.library:NiceUrl(@id)}">
              <xsl:if test="contains(@nodeName, 'commerce')">
                <xsl:attribute name="class">menuHeaderCommerceA</xsl:attribute>
              </xsl:if>
              <xsl:if test="contains(@nodeName, 'corporate')">
                <xsl:attribute name="class">menuHeaderCorporateA</xsl:attribute>
              </xsl:if>
              <xsl:comment /><!--prevent self-close -->
              <span class="leftDiv"><!-- test -->&nbsp;</span>
              <span class="middleDiv">
                <!-- test -->
                <xsl:choose>
                  <xsl:when test="$menuName != ''">
                    <xsl:attribute name="title"><xsl:value-of select="$menuName"/></xsl:attribute>
                    <xsl:value-of select="$menuName"/><xsl:comment /><!-- Prevent self-closing element -->       
                  </xsl:when>
                  <xsl:otherwise>
                    <xsl:attribute name="title"><xsl:value-of select="@nodeName"/></xsl:attribute>
                    <xsl:value-of select="@nodeName"/><xsl:comment /><!-- Prevent self-closing element -->
                  </xsl:otherwise>
                </xsl:choose>
              </span>
              <span class="rightDiv"><!-- test -->&nbsp;</span>
            </a>        
             <xsl:call-template name="subItem" >
                <xsl:with-param name="parentPage"><xsl:value-of select="@id" /></xsl:with-param>
              </xsl:call-template>
          </li>
        </xsl:for-each>
        
      </ul>
    </xsl:template>        

    <xsl:template name="subItem">
    <xsl:param name="parentPage" />
    <xsl:variable name="parentLevel" select="umbraco.library:GetXmlNodeById($parentPage)/@level" />
    <xsl:comment><!-- --></xsl:comment>
    <xsl:if test="umbraco.library:GetXmlNodeById($parentPage)/@level > 1">
      <xsl:if test="count(umbraco.library:GetXmlNodeById($parentPage)/descendant::*[@isDoc and not (self::Website) and not(self::Event) and string(naviHide) != '1']) &gt; 0">
      <ul><xsl:comment />
        <xsl:for-each select="umbraco.library:GetXmlNodeById($parentPage)/descendant::*[@isDoc and not (self::Website) and (@level - $parentLevel = 1) and umbraco.library:HasAccess(@id,@path) and string(naviHide) != '1']">
          <xsl:sort select="@level"/>
          <xsl:sort select="@sortOrder" data-type="number" order="ascending" />
          <xsl:variable name="menuName" select="menuName"/>
          <li>
            <xsl:if test="$currentPage/@nodeName = @nodeName or ($currentPage/ancestor::*[@isDoc and not (self::Website)]/@nodeName = @nodeName)">
              <xsl:attribute name="class">active</xsl:attribute>
            </xsl:if>
            <a href="{umbraco.library:NiceUrl(@id)}"><xsl:comment /><!-- Prevent self-closing element -->
              <span class="leftDiv"><!-- test -->&nbsp;</span>
              <span class="middleDiv">
                <!-- test -->
                <xsl:choose>
                  <xsl:when test="$menuName != ''">
                    <xsl:attribute name="title"><xsl:value-of select="$menuName"/></xsl:attribute>
                    <xsl:value-of select="$menuName"/><xsl:comment /><!-- Prevent self-closing element -->       
                  </xsl:when>
                  <xsl:otherwise>
                    <xsl:attribute name="title"><xsl:value-of select="@nodeName"/></xsl:attribute>
                    <xsl:value-of select="@nodeName"/><xsl:comment /><!-- Prevent self-closing element -->
                  </xsl:otherwise>
                </xsl:choose>
              </span>
              <span class="rightDiv"><!-- test -->&nbsp;</span>
            </a>
          </li>
        </xsl:for-each>
      </ul>
      </xsl:if>
    </xsl:if>
    </xsl:template>

    </xsl:stylesheet>
  • Ferdy Hoefakker 214 posts 248 karma points
    Mar 07, 2013 @ 10:25
    Ferdy Hoefakker
    0

    Anyone?

  • Alex Skrypnyk 6163 posts 24143 karma points MVP 8x admin c-trib
    Mar 07, 2013 @ 11:32
    Alex Skrypnyk
    0

    Hi, Ferdy

    Why do you use 'descendant-or-self' and 'ancestor-or-self'? at one time?

     

    $currentPage/ancestor-or-self::*[@isDoc]/descendant-or-self::*[@isDoc]
     [umbraco.library:HasAccess(@id,@path)  and string(naviHide) != '1' and
    (self::Nieuws or self::Pagina) and @level &gt; 0]
  • Alex Skrypnyk 6163 posts 24143 karma points MVP 8x admin c-trib
    Mar 07, 2013 @ 11:34
    Alex Skrypnyk
    0
    descendant-or-self 

    Grabs all children nodes. I think it's bottleneck

  • Ferdy Hoefakker 214 posts 248 karma points
    Mar 07, 2013 @ 11:59
    Ferdy Hoefakker
    0

    It's to build up the menu correctly. No matter the current page I am on, I ALWAYS want to start from the top. So, using ancestor-or-self I go to the root, and then grab everything below it.

    As I stated, I am pretty sure that is indeed the bottleneck. But I have no idea what would be a more efficient XPATH expression. Maybe I should add my node structure:

    root
    -website Dutch
    - - store news
    - - - categories
    - - - - news posts
    - - corporate news
    - - - categories
    - - - - news posts
    - - page with a form
    - - login page
    - - acces denied page
    -website Flemish
    - - store news
    - - - categories
    - - - - news posts
    - - corporate news
    - - - categories
    - - - - news posts
    - - page with a form
    - - login page
    - - acces denied page
    -website French
    - - store news
    - - - categories
    - - - - news posts
    - - corporate news
    - - - categories
    - - - - news posts
    - - page with a form
    - - login page
    - - acces denied page

    Whatever page I am on, I need to build a menu for the corresponding site (Dutch, Flemish or French). The menu items are the categories under the two news types (store and corporate). Not only that, but I need to start with a header for the store news, then display all it's categories. This is followed by a header for the corporate news which in turn has all its categories under it as menu items.

    I hope I explained this clearly enough.

    -Ferdy

  • Alex Skrypnyk 6163 posts 24143 karma points MVP 8x admin c-trib
    Mar 07, 2013 @ 12:20
    Alex Skrypnyk
    0

    Ferdy, could you give me link to your site ? ))

  • Ferdy Hoefakker 214 posts 248 karma points
    Mar 07, 2013 @ 12:22
    Ferdy Hoefakker
    0

    Afraid not, it's behind a login and contains sensitive information.

  • Alex Skrypnyk 6163 posts 24143 karma points MVP 8x admin c-trib
    Mar 07, 2013 @ 12:22
    Alex Skrypnyk
    0

    i think you shold remove this verification

    <xsl:iftest="count(umbraco.library:GetXmlNodeById($parentPage)/descendant::*[@isDoc
     and not (self::Website) and not(self::Event) and string(naviHide) !=
    '1']) &gt; 0"
    >

     

  • Alex Skrypnyk 6163 posts 24143 karma points MVP 8x admin c-trib
    Mar 07, 2013 @ 12:31
    Alex Skrypnyk
    100
    <xsl:for-eachselect="$currentPage/ancestor-or-self::*[@isDoc]/descendant-or-self::*[@isDoc]
     [umbraco.library:HasAccess(@id,@path)  and string(naviHide) != '1' and
    (self::Nieuws or self::Pagina) and @level &gt; 0]"
    >

    and this part should be like this:

    <xsl:for-eachselect="$currentPage/ancestor-or-self::*[@isDoc]/*[@isDoc]
     [umbraco.library:HasAccess(@id,@path)  and string(naviHide) != '1' and
    (self::Nieuws or self::Pagina) and @level &gt; 0]"
    >

    we don't need to grab all nodes each time, we have for-each in child template, there are we would only traverse on first level of pages


  • Alex Skrypnyk 6163 posts 24143 karma points MVP 8x admin c-trib
    Mar 07, 2013 @ 12:33
    Alex Skrypnyk
    0

    you could build menu without any descendant axes

  • Alex Skrypnyk 6163 posts 24143 karma points MVP 8x admin c-trib
    Mar 07, 2013 @ 12:35
    Alex Skrypnyk
    0
    <xsl:with-paramname="parentPage"><xsl:value-ofselect="@id"/></xsl:with-param>

    why do you pass id into template ?

    passing all item is more optimal, and you don't need do this operation

    umbraco.library:GetXmlNodeById($parentPage)
  • Ferdy Hoefakker 214 posts 248 karma points
    Mar 07, 2013 @ 12:52
    Ferdy Hoefakker
    0

    Okay, removing the descendant-or-self on the first loop fixes it. It went from 5s on average to 0.5s difference between before- and after performing transformation.

    Your second suggestion is noted, but I think the above will already be more than enough. Not sure if I will be given the time to restructure the entire sub item template to accomodate such a change =\

    In any case, thanks!

    -Ferdy

  • Alex Skrypnyk 6163 posts 24143 karma points MVP 8x admin c-trib
    Mar 07, 2013 @ 12:55
    Alex Skrypnyk
    0

    It's my pleasure.

    We could cooperate) if you have a lot of umbraco projects )

    Alex )

Please Sign in or register to post replies

Write your reply to:

Draft