What I need to do is sort a Media folder of documents by a custom property call dateGenerated. I've sorted the list in descending order and would like to list it out and demarkate the list by years. In order to do this I need to compare the last item in the sorted for-each with the current item and if the year does not match then print out the year label. I've been unable to make any headway on this as it is sorted so using xslt siblings is grabbing the non sorted node. Any help would be greatly appretiated.
You're right - you can't use the *-sibling:: axes when you're sorting, because they always work on document order. What you need to do, is to search the forum (and maybe Google) for "XSLT grouping" and you should probably look into a technique called "Muenchian Grouping" - I'll cook up an example for you if you like, but first I'll need to ask about the months: Are you going to group by month too or will there only be a single node (i.e., "April Financials") for each month?
You could always sort the nodes, store them in a var and then loop through that nodeset using the preceding-sibling method (I'm sure Chriztian will come up with some killer one liner though ;) )
@Chriztian - Impressive, works like a charm. I had already made a user control to do the same thing once I had enough of trying to get it to work in xsl. This is a sweet way of grouping. I'm going to replace my user control with this snazzy little piece of code.
for-each and previous node comparison
Hi,
What I need to do is sort a Media folder of documents by a custom property call dateGenerated. I've sorted the list in descending order and would like to list it out and demarkate the list by years. In order to do this I need to compare the last item in the sorted for-each with the current item and if the year does not match then print out the year label. I've been unable to make any headway on this as it is sorted so using xslt siblings is grabbing the non sorted node. Any help would be greatly appretiated.
<xsl:template match="/">
<xsl:variable name="myNodes" select="umbraco.library:GetMedia(1216,'true')/descendant-or-self::*[@nodeTypeAlias='File']" />
<ul id="docList">
<xsl:for-each select="$myNodes">
<xsl:sort select="./dateGenerated" order="descending" />
<xsl:variable name="thisYear" select="umbraco.library:FormatDateTime(./dateGenerated, 'yyyy')"/>
<xsl:variable name="thisMonth" select="umbraco.library:FormatDateTime(./dateGenerated, 'MMMM')"/>
<!-- I would like to compare the previous node year with the current so I can print out a new year header -->
<li>
<a href="{./umbracoFile}" target="_blank">
<xsl:value-of select="$thisMonth"/>
</a>
</li>
</xsl:for-each>
</ul>
</xsl:template>
Desired output
2010
August Financials
April Financials
February Financials
2009
December Financials
September Financials
May Financials
2008
etc etc
Thanks
Eric
Hey Eric,
You'll want to look into the preceding-sibling::* axis.
Off the top of my head, something like this should work
Matt
Hi Eric,
You're right - you can't use the *-sibling:: axes when you're sorting, because they always work on document order. What you need to do, is to search the forum (and maybe Google) for "XSLT grouping" and you should probably look into a technique called "Muenchian Grouping" - I'll cook up an example for you if you like, but first I'll need to ask about the months: Are you going to group by month too or will there only be a single node (i.e., "April Financials") for each month?
/Chriztian
Hi,
This doesn't work as preceding-sibling is giving me the previous node in the unsorted. I need to get the previous node in my sorted list.
@Matt BTW - I just started using the Desktop Media Upload....very nice tool.
Eric
Hey Eric,
You could always sort the nodes, store them in a var and then loop through that nodeset using the preceding-sibling method (I'm sure Chriztian will come up with some killer one liner though ;) )
Glad you're liking DMU
Matt
@Matt: HA :-) Tough one, though, technically it's possible (most XSLT should work fine collapsed to a single line) but doesn't really count :-)
@Eric: Here's a "textbook" Muenchian Grouping example:
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:umbraco.library="urn:umbraco.library" exclude-result-prefixes="umbraco.library" > <xsl:output method="xml" indent="yes" omit-xml-declaration="yes" /> <xsl:param name="currentPage" /> <xsl:variable name="myNodes" select="umbraco.library:GetMedia(1216, true())/descendant-or-self::*[@nodeTypeAlias = 'File']" /> <!-- Create a key (index) on File elements indexed by year --> <xsl:key name="file-by-year" match="*[@nodeTypeAlias = 'File']" use="substring(dateGenerated, 1, 4)" /> <xsl:template match="/"> <!-- This finds the first node in every year group --> <xsl:for-each select="$myNodes[count(. | key('file-by-year', substring(dateGenerated, 1, 4))[1]) = 1]"> <xsl:sort select="dateGenerated" order="descending" /> <!-- Process the once-per-group info (i.e., write the header) --> <xsl:apply-templates select="." mode="group" /> <ul> <!-- Process each item in this group --> <xsl:apply-templates select="key('file-by-year', substring(dateGenerated, 1, 4))" mode="item"> <xsl:sort select="dateGenerated" order="descending" /> </xsl:apply-templates> </ul> </xsl:for-each> </xsl:template> <!-- Output for group header (applied once per group) --> <xsl:template match="*[@nodeTypeAlias = 'File']" mode="group"> <h2> <xsl:value-of select="substring(dateGenerated, 1, 4)" /> </h2> </xsl:template> <!-- Output for each item in the group --> <xsl:template match="*[@nodeTypeAlias = 'File']" mode="item"> <li> <a href="{umbracoFile}" title="{umbracoFile}" target="_blank"> <xsl:value-of select="umbracoFile" /> </a> </li> </xsl:template> </xsl:stylesheet>
/Chriztian
@Chriztian - Impressive, works like a charm. I had already made a user control to do the same thing once I had enough of trying to get it to work in xsl. This is a sweet way of grouping. I'm going to replace my user control with this snazzy little piece of code.
Thanks
Eric
Great! I guess that's 1-0 to XSLT, then :-)
/Chriztian
Sweet. This is why I love trying to answer the XSLT questions, you can rest assured Chriztian will come in with a stonker =)
Awesome example
Matt
is working on a reply...