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>&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.
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).
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?
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 " "> ]>
<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('<li>')"/>
<xsl:variable name="closeTag" select="string('</li>')"/>
<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>&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.
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).
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
Any idea's on how to achieve this would be fantastic.
Thanks, Laurie
Nb. The param ID is just hardcoded in at the moment, to test the template works (which it does).
If you want the direct children of the current ID in your for-each, you would do something like:
Then, loop over the subItems in your getRecord template passing subItems in as a param.
HTH,
Nik
Right, replace the hardcoded value with the subItms variable (which is a collection of nodes). And then, your templte for-each would select $subItems.
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
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!
Hi Laurence, please make sure that you are specifying at least the / in your xPath. So, you getRecord for-each should say:
NOTE: UmbracoNaviHide optional, but recommended as standard practice.
Does it work then?
Thanks,
Nik
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.
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
FOr the sake of debugging and eliminating the mod as the issue. Can you output your 9 "parents" with o/ a problem?
Yes my output looks like...
This is the correct amount of <li> tags.
Ok, can you also send the entire XSLT or email it to me nwahlberg {at} scandiaconsulting dot com
Thanks!
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?
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.
I hope this is what you were looking for! Let me know if it isn't and I'll try again.
Cheers,
Nik
Sorry, correction for above. Replace 'DailyNewsClip' with the name of your document type.
Thanks,
Nik
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
NP, just let me know if you run into any snags...
Hi Laurence (+ Nik),
This is how I'd approach this in XSLT:
/Chriztian
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
Nice! I like Chriztian's solution. Thanks for adding to this discussion.
-- Nik
One thing, shouldn't
$data[position() mod $group-size = 1]
be
$data[position() mod $group-size = 0]
Or am I reading this wrong...
Thanks.
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
Duh! That makes total sense. Sorry for the stupid question...
Hey - no worries :-)
Could easily have made the same error myself upon just looking at a piece of, say, .NET code :-)
is working on a reply...