Copied to clipboard

Flag this post as spam?

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


  • Laurence Gillian 600 posts 1219 karma points
    Jan 25, 2010 @ 17:48
    Laurence Gillian
    0

    Grouping Nodes and Loading in Children

    Hello,

    I am working on a project where I need to group a set of nodes.

    Example.

    I have 32 nodes.

    These need to be grouped into groups of 9s.

    Once they are grouped, we need to load the related nodes into the group.

    So far I have got this. Which creates the groups, however I am struggling to work out a way to pass the children ID's into the call-template to load the data.

    Example Code

    <xsl:param name="currentPage"/>
      <xsl:variable name="group-size">9</xsl:variable>
      <xsl:template match="/">
    
    <!-- Fresh Ways always come on Mondays -->
    
        <ul>
          <xsl:for-each select="$currentPage/descendant::node [(position() mod $group-size) = 1]">
            <li>
    
              <!-- TO DO - List ID's in this group -->
              <!-- Pass ID's into the call template below... -->
              <xsl:call-template name="getRecord">
                <xsl:with-param name="xmlID" select="1106"></xsl:with-param>
              </xsl:call-template>
    
            </li>
          </xsl:for-each>
        </ul>
    
    
      </xsl:template>
    
      <xsl:template name="getRecord">
        <xsl:param name="xmlID" select="'not set'" />
        <xsl:for-each select="umbraco.library:GetXmlNodeById($xmlID)">
          <xsl:variable name="galImage" select="data [@alias = 'mediaImage1']"/>
          <span class="clip">
            <a>
              <xsl:attribute name="href">
                <xsl:value-of select="umbraco.library:NiceUrl(@id)"/>
              </xsl:attribute>
              <xsl:attribute name="title">
                <xsl:text>View </xsl:text>
                <xsl:value-of select="data [@alias = 'workTitle']" />
              </xsl:attribute>
              <img>
                <xsl:attribute name="alt">
                  <xsl:value-of select="data [@alias = 'workTitle']" />
                </xsl:attribute>
                <xsl:attribute name="src">
                  <xsl:text>/umbraco/ImageGen.ashx?image=</xsl:text>
                  <xsl:value-of select="$galImage"/>
                  <xsl:text>&amp;height=135</xsl:text>
                </xsl:attribute>
              </img>
            </a>
          </span>
        </xsl:for-each>
    
    </xsl:template>

    Any idea's on how to achieve this would be fantastic.

    Thanks, Laurie

  • Laurence Gillian 600 posts 1219 karma points
    Jan 25, 2010 @ 17:51
    Laurence Gillian
    0

    Nb. The param ID is just hardcoded in at the moment, to test the template works (which it does).

  • Nik Wahlberg 639 posts 1237 karma points MVP
    Jan 25, 2010 @ 17:52
    Nik Wahlberg
    1

    If you want the direct children of the current ID in your for-each, you would do something like: 

    <xsl:variable name="subItems" select="umbraco.library:GetXmlNodeById(@id)/node [string(data [@alias='umbracoNaviHide']) != '1'"/>

    Then, loop over the subItems in your getRecord template passing subItems in as a param. 

    HTH,
    Nik

  • Nik Wahlberg 639 posts 1237 karma points MVP
    Jan 25, 2010 @ 17:54
    Nik Wahlberg
    0

    Right, replace the hardcoded value with the subItms variable (which is a collection of nodes). And then, your templte for-each would select $subItems. 

  • Laurence Gillian 600 posts 1219 karma points
    Jan 25, 2010 @ 18:04
    Laurence Gillian
    0

    Hmm, just tried that and don't seem to be having any luck.

    Just had a look at what is coming back off my 'for-each select' statement and it seems to be nesting the data quite horribly.

    /Laurie

     

  • Laurence Gillian 600 posts 1219 karma points
    Jan 25, 2010 @ 18:26
    Laurence Gillian
    0

    This is my updated code. Which is successfully pulling in the first set of 9, but not the others. 

    I know its pretty close, its a case of me losing context on what the XSL is doing!

    <ul>
          <xsl:for-each select="$currentPage/descendant::node [(position() mod $group-size) = 1]">
            <li>
              <xsl:variable name="position" select="position()" />
              <xsl:value-of select="$position"/>
    
              <xsl:for-each select="node[($position mod $group-size) = 1] [string(data [@alias='mediaImage1']) != '']">
                <xsl:call-template name="getRecord">
                  <xsl:with-param name="xmlID" select="@id"></xsl:with-param>
                </xsl:call-template>
              </xsl:for-each>
    
            </li>
          </xsl:for-each>
        </ul>
  • Nik Wahlberg 639 posts 1237 karma points MVP
    Jan 25, 2010 @ 18:50
    Nik Wahlberg
    0

    Hi Laurence, please make sure that you are specifying at least the / in your xPath. So, you getRecord for-each should say:

     

    <xsl:template name="getRecord">
       
    <xsl:param name="xmlID" select="'not set'" />
       
    <xsl:for-each select="umbraco.library:GetXmlNodeById($xmlID)/node [string(data [@alias='umbracoNaviHide']) != '1'">
         
    <xsl:variable name="galImage" select="data [@alias = 'mediaImage1']"/>
         
    <span class="clip">
           
    <a>
             
    <xsl:attribute name="href">
               
    <xsl:value-of select="umbraco.library:NiceUrl(@id)"/>
             
    </xsl:attribute>
             
    <xsl:attribute name="title">
               
    <xsl:text>View </xsl:text>
               
    <xsl:value-of select="data [@alias = 'workTitle']" />
             
    </xsl:attribute>
             
    <img>
               
    <xsl:attribute name="alt">
                 
    <xsl:value-of select="data [@alias = 'workTitle']" />
               
    </xsl:attribute>
               
    <xsl:attribute name="src">
                 
    <xsl:text>/umbraco/ImageGen.ashx?image=</xsl:text>
                 
    <xsl:value-of select="$galImage"/>
                 
    <xsl:text>&amp;height=135</xsl:text>
               
    </xsl:attribute>
             
    </img>
           
    </a>
         
    </span>
       
    </xsl:for-each>

    NOTE: UmbracoNaviHide optional, but recommended as standard practice. 

    Does it work then?

    Thanks,
    Nik

  • Laurence Gillian 600 posts 1219 karma points
    Jan 25, 2010 @ 18:57
    Laurence Gillian
    0

    That doesn't work :(

    The idea behind that is we are getting the XML data just for one node, because getRecord is run 9 times because of the for-each loop it sits within. Each time it is run a different ID is passed across.

    I've had a quick play around and it seems this code only works for position 1, not for instance 2 or 3. This makes me think there is an issue with my mod function and the way I am using position.

    <xsl:for-each select="node[($position mod $group-size) = 1] [string(data [@alias='mediaImage1']) != '']">

    Thanks again for your help :) and yep UmbracoNaviHide will be added (just taken it out for the time being to make the code quicker to read).

    /Laurie

  • Nik Wahlberg 639 posts 1237 karma points MVP
    Jan 25, 2010 @ 19:03
    Nik Wahlberg
    0

    FOr the sake of debugging and eliminating the mod as the issue. Can you output your 9 "parents" with o/ a problem? 

  • Laurence Gillian 600 posts 1219 karma points
    Jan 25, 2010 @ 19:09
    Laurence Gillian
    0

    Yes my output looks like...

    This is the correct amount of <li> tags.

    <ul>
        <li>
            <span class="clip">data...</span>
            <span class="clip">data...</span>
            <span class="clip">data...</span>
            <span class="clip">data...</span>
            <span class="clip">data...</span>
            <span class="clip">data...</span>
            <span class="clip">data...</span>
            <span class="clip">data...</span>
            <span class="clip">data...</span>
        </li>
        <li>2
        </li>
        <li>3
        </li>
    </ul>
    

  • Nik Wahlberg 639 posts 1237 karma points MVP
    Jan 25, 2010 @ 20:28
    Nik Wahlberg
    0

    Ok, can you also send the entire XSLT or email it to me nwahlberg {at} scandiaconsulting dot com

    Thanks!

  • Sebastiaan Janssen 5060 posts 15522 karma points MVP admin hq
    Jan 25, 2010 @ 20:38
    Sebastiaan Janssen
    1

    Beh, I'm not seeing it, but the double for-each (both with the mod 9) seems totally wrong to me, it should me something like IF this is the 9th, then do something. 

    It seems like the mod should not be in the for-each function, but in an if. Does that make sense?

  • Nik Wahlberg 639 posts 1237 karma points MVP
    Jan 25, 2010 @ 22:37
    Nik Wahlberg
    1

    Alright, I think I have your solution (if I understood the requirements right). Here's what the 'grouping' looks like. It's really a chunking of the nodes. Please note, XSL will not allow you to have orphaned open/close tags (as you may know), so instead I've used literals to represent the start and end tags of the list item and then finally disabled the output escaping. 

    <?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" xmlns:Exslt.ExsltCommon="urn:Exslt.ExsltCommon" xmlns:Exslt.ExsltDatesAndTimes="urn:Exslt.ExsltDatesAndTimes" xmlns:Exslt.ExsltMath="urn:Exslt.ExsltMath" xmlns:Exslt.ExsltRegularExpressions="urn:Exslt.ExsltRegularExpressions" xmlns:Exslt.ExsltStrings="urn:Exslt.ExsltStrings" xmlns:Exslt.ExsltSets="urn:Exslt.ExsltSets" 
        exclude-result-prefixes="msxml umbraco.library Exslt.ExsltCommon Exslt.ExsltDatesAndTimes Exslt.ExsltMath Exslt.ExsltRegularExpressions Exslt.ExsltStrings Exslt.ExsltSets ">
    
      <xsl:output method="html" omit-xml-declaration="yes"/>
      <xsl:param name="currentPage"/>
    
      <xsl:variable name="documentTypeAlias" select="string('DailyNewsClip')"/>
      <xsl:variable name="openTag" select="string('&lt;li&gt;')"/>
      <xsl:variable name="closeTag" select="string('&lt;/li&gt;')"/>
      <xsl:variable name="data" select="umbraco.library:GetXmlAll()/descendant-or-self::node [@nodeTypeAlias = $documentTypeAlias and string(data [@alias='umbracoNaviHide']) != '1']"/>
      <xsl:variable name="group-size" select="string('9')" />
      <xsl:template match="/">
        <!-- Fresh Ways always come on Mondays -->
        <ul>
          <!-- Start the very first list item -->
          <xsl:value-of select="$openTag" disable-output-escaping="yes"/>
          <xsl:for-each select="$data">
            <xsl:variable name="galImage" select="data [@alias = 'mediaImage1']"/>
            <span class="clip">
              <a>
                <xsl:attribute name="href">
                  <xsl:value-of select="umbraco.library:NiceUrl(@id)"/>
                </xsl:attribute>
                <xsl:attribute name="title">
                  <xsl:text>View </xsl:text>
                  <xsl:value-of select="data [@alias = 'workTitle']" />
                </xsl:attribute>
                <img>
                  <xsl:attribute name="alt">
                    <xsl:value-of select="data [@alias = 'workTitle']" />
                  </xsl:attribute>
                  <xsl:attribute name="src">
                    <xsl:text>/umbraco/ImageGen.ashx?image=</xsl:text>
                    <xsl:value-of select="$galImage"/>
                    <xsl:text>&amp;height=135</xsl:text>
                  </xsl:attribute>
                </img>
              </a>
            </span>
    
            <!-- if this is the ninth item, then close the LI and open a new one -->
            <xsl:if test="position() mod 9 = 0">
              <xsl:value-of select="$closeTag" disable-output-escaping="yes"/>
              <xsl:value-of select="$openTag" disable-output-escaping="yes"/>
            </xsl:if>
          </xsl:for-each>
          <!-- We have to close the last item in the list here -->
          <xsl:value-of select="$closeTag" disable-output-escaping="yes"/>
        </ul>
      </xsl:template>
    </xsl:stylesheet>
    

    I hope this is what you were looking for! Let me know if it isn't and I'll try again. 

    Cheers,
    Nik

  • Nik Wahlberg 639 posts 1237 karma points MVP
    Jan 25, 2010 @ 22:42
    Nik Wahlberg
    1

    Sorry, correction for above. Replace 'DailyNewsClip' with the name of your document type. 

    Thanks,
    Nik

  • Laurence Gillian 600 posts 1219 karma points
    Jan 26, 2010 @ 00:15
    Laurence Gillian
    0

    Thanks Nik,

    I'll give this a go tomorrow, looks perfect though running it though my mind which every now and again thinks in XSL!

    Should be really easy to implement filtering as well, as its just the start node that changes :)

    I'll let you know how it goes, however I think I'll be coming back and marking that as the solution.

    Thanks again for your time, Lau

  • Nik Wahlberg 639 posts 1237 karma points MVP
    Jan 26, 2010 @ 01:49
    Nik Wahlberg
    0

    NP, just let me know if you run into any snags...

  • Chriztian Steinmeier 2800 posts 8790 karma points MVP 8x admin c-trib
    Jan 26, 2010 @ 10:03
    Chriztian Steinmeier
    2

    Hi Laurence (+ Nik),

    This is how I'd approach this in 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" xmlns:Exslt.ExsltCommon="urn:Exslt.ExsltCommon" xmlns:Exslt.ExsltDatesAndTimes="urn:Exslt.ExsltDatesAndTimes" xmlns:Exslt.ExsltMath="urn:Exslt.ExsltMath" xmlns:Exslt.ExsltRegularExpressions="urn:Exslt.ExsltRegularExpressions" xmlns:Exslt.ExsltStrings="urn:Exslt.ExsltStrings" xmlns:Exslt.ExsltSets="urn:Exslt.ExsltSets" 
        exclude-result-prefixes="msxml umbraco.library Exslt.ExsltCommon Exslt.ExsltDatesAndTimes Exslt.ExsltMath Exslt.ExsltRegularExpressions Exslt.ExsltStrings Exslt.ExsltSets ">
    
        <xsl:output method="html" omit-xml-declaration="yes" />
        <xsl:param name="currentPage" />
    
        <xsl:variable name="root" select="$currentPage/ancestor-or-self::node[@level = 1]" />
    
        <xsl:variable name="documentTypeAlias" select="'DailyNewsClip'"/>
    
        <xsl:variable name="data" select="$root/descendant-or-self::node[@nodeTypeAlias = $documentTypeAlias][not(data[@alias = 'umbracoNaviHide']) = 1]" />
    
        <xsl:variable name="group-size" select="9" />
    
        <xsl:template match="/">
              <ul>
                  <xsl:apply-templates select="$data[position() mod $group-size = 1]" mode="group" />
              </ul>
        </xsl:template>
    
        <xsl:template match="node" mode="group">
          <li>
                <xsl:apply-templates select=". | following-sibling::node[@nodeTypeAlias = $documentTypeAlias][not(data[@alias = 'umbracoNaviHide'] = 1)][position() &lt; $group-size]" mode="item" />
          </li>
        </xsl:template>
    
        <!-- The desired output of a node -->
        <xsl:template match="node" mode="item">
            <xsl:variable name="galImage" select="data[@alias = 'mediaImage1']" />
            <span class="clip">
                <a href="{umbraco.library:NiceUrl(@id)}" title="View {data[@alias = 'workTitle']}">
                    <img src="/umbraco/ImageGen.ashx?image={$galImage}&amp;height=135" alt="{data[@alias = 'workTitle']}" />
                </a>
              </span>
        </xsl:template>
    
    </xsl:stylesheet>
    

    /Chriztian

  • Laurence Gillian 600 posts 1219 karma points
    Jan 26, 2010 @ 10:54
    Laurence Gillian
    0

    Ah interesting 'apply-templates' match node was how I was trying to tackle this earlier in the day yesterday. But I couldn't get it to play ball.

    Looking forward to testing both of these solutions. 

    Thanks again, Lau

  • Nik Wahlberg 639 posts 1237 karma points MVP
    Jan 26, 2010 @ 13:38
    Nik Wahlberg
    0

    Nice! I like Chriztian's solution. Thanks for adding to this discussion. 

    -- Nik

  • Nik Wahlberg 639 posts 1237 karma points MVP
    Jan 26, 2010 @ 13:39
    Nik Wahlberg
    0

    One thing, shouldn't

    $data[position() mod $group-size = 1]

    be

    $data[position() mod $group-size = 0]

    Or am I reading this wrong...

    Thanks.

  • Chriztian Steinmeier 2800 posts 8790 karma points MVP 8x admin c-trib
    Jan 26, 2010 @ 15:16
    Chriztian Steinmeier
    0

    Hi Nik,

    No, it's actually correct, because in my version I look for the first item in every chunk (1, 10, 19 etc), whereas your version does the check at the end (matching 9, 18, 27 etc).

     /Chriztian

  • Nik Wahlberg 639 posts 1237 karma points MVP
    Jan 26, 2010 @ 19:32
    Nik Wahlberg
    0

    Duh! That makes total sense. Sorry for the stupid question...

  • Chriztian Steinmeier 2800 posts 8790 karma points MVP 8x admin c-trib
    Jan 26, 2010 @ 20:00
    Chriztian Steinmeier
    1

    Hey - no worries :-)

    Could easily have made the same error myself upon just looking at a piece of, say, .NET code :-)

Please Sign in or register to post replies

Write your reply to:

Draft