views:

150

answers:

3

Update

I'd like to appologize to the people who provided answers, I seem to have caused all sorts of confusion. To avoid complicating things even further, I've removed the previous code and have added new information. Read on...

I'm working on a custom Blog in Umbraco. Umbraco spits out XML as the output which is then read using XSLT.

The structure of the XML is as follows

  • Blog
    • Blog Centre
      • Room
        • Blog Post
        • Blog Post
        • Blog Post
      • Room
        • Blog Post
    • Blog Centre
      • Room
        • Blog Post

Here's the XML code, I've cleaned up a lot of it to make it at least somewhat readable.

<Blog id="1078" parentID="1049" level="2" writerID="0" creatorID="0" nodeType="1073" template="1089" sortOrder="7" createDate="2010-09-27T14:11:04" updateDate="2010-10-12T16:59:12" nodeName="Blog" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078" isDoc="">
    <newPageTitle>The Lorem Ipsum Blog</newPageTitle>
    <BlogCentre id="1079" parentID="1078" level="3" writerID="0" creatorID="0" nodeType="1075" template="1076" sortOrder="1" createDate="2010-09-27T14:11:49" updateDate="2010-10-07T14:43:13" nodeName="Blog Centre 1" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1079" isDoc="">
        <Room id="1081" parentID="1079" level="4" writerID="0" creatorID="0" nodeType="1077" template="0" sortOrder="1" createDate="2010-09-27T14:12:26" updateDate="2010-10-07T14:43:06" nodeName="Room 10" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1079,1081" isDoc="">
            <BlogPost id="1175" parentID="1081" level="5" writerID="0" creatorID="0" nodeType="1087" template="1192" sortOrder="1" createDate="2010-10-07T14:51:48" updateDate="2010-10-12T21:30:53" nodeName="The first ever Blog post" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1079,1081,1175" isDoc="">
                <topicTitle>The first ever blog</topicTitle>
            </BlogPost>
            <BlogPost id="1180" parentID="1081" level="5" writerID="0" creatorID="3" nodeType="1087" template="1089" sortOrder="2" createDate="2010-10-08T15:52:20" updateDate="2010-10-12T16:57:00" nodeName="asdasd" writerName="Administrator" creatorName="ZX" path="-1,1049,1078,1079,1081,1180" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
            </BlogPost>
            <BlogPost id="1181" parentID="1081" level="5" writerID="0" creatorID="0" nodeType="1087" template="1089" sortOrder="3" createDate="2010-10-08T17:50:19" updateDate="2010-10-12T11:40:37" nodeName="condimentum" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1079,1081,1181" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
                <archiveUnder>2010-09-01T00:00:00</archiveUnder>
            </BlogPost>
            <BlogPost id="1194" parentID="1081" level="5" writerID="0" creatorID="0" nodeType="1087" template="1089" sortOrder="4" createDate="2010-10-12T11:41:50" updateDate="2010-10-12T11:42:37" nodeName="Nam augue" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1079,1081,1194" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
                <archiveUnder>2010-08-05T00:00:00</archiveUnder>
            </BlogPost>
            <BlogPost id="1195" parentID="1081" level="5" writerID="0" creatorID="0" nodeType="1087" template="1089" sortOrder="5" createDate="2010-10-12T11:42:15" updateDate="2010-10-12T11:42:25" nodeName="consequat nunc" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1079,1081,1195" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
                <archiveUnder>2010-08-12T00:00:00</archiveUnder>
            </BlogPost>
            <BlogPost id="1196" parentID="1081" level="5" writerID="0" creatorID="0" nodeType="1087" template="1089" sortOrder="6" createDate="2010-10-12T12:05:57" updateDate="2010-10-12T12:08:40" nodeName="cursus congue" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1079,1081,1196" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
                <archiveUnder>2009-10-22T00:00:00</archiveUnder>
            </BlogPost>
            <BlogPost id="1197" parentID="1081" level="5" writerID="0" creatorID="0" nodeType="1087" template="1089" sortOrder="7" createDate="2010-10-12T12:08:54" updateDate="2010-10-12T12:09:24" nodeName="inceptos" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1079,1081,1197" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
                <archiveUnder>2009-11-19T00:00:00</archiveUnder>
            </BlogPost>
            <BlogPost id="1198" parentID="1081" level="5" writerID="0" creatorID="0" nodeType="1087" template="1089" sortOrder="8" createDate="2010-10-12T12:09:45" updateDate="2010-10-12T12:10:13" nodeName="inceptos himenaeos" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1079,1081,1198" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
                <archiveUnder>2009-12-16T00:00:00</archiveUnder>
            </BlogPost>
            <BlogPost id="1199" parentID="1081" level="5" writerID="0" creatorID="0" nodeType="1087" template="1089" sortOrder="9" createDate="2010-10-12T12:10:29" updateDate="2010-10-12T12:10:56" nodeName="consequat" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1079,1081,1199" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
                <archiveUnder>2010-01-13T00:00:00</archiveUnder>
            </BlogPost>
            <BlogPost id="1200" parentID="1081" level="5" writerID="0" creatorID="0" nodeType="1087" template="1089" sortOrder="10" createDate="2010-10-12T12:11:08" updateDate="2010-10-12T12:11:35" nodeName="himenaeos" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1079,1081,1200" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
                <archiveUnder>2010-02-09T00:00:00</archiveUnder>
            </BlogPost>
            <BlogPost id="1201" parentID="1081" level="5" writerID="0" creatorID="0" nodeType="1087" template="1089" sortOrder="11" createDate="2010-10-12T12:11:45" updateDate="2010-10-12T12:12:35" nodeName="cursus congue" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1079,1081,1201" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
                <archiveUnder>2010-04-22T00:00:00</archiveUnder>
            </BlogPost>
            <BlogPost id="1202" parentID="1081" level="5" writerID="0" creatorID="0" nodeType="1087" template="1089" sortOrder="12" createDate="2010-10-12T12:12:18" updateDate="2010-10-12T12:12:45" nodeName="pharetra" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1079,1081,1202" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
                <archiveUnder>2010-03-09T00:00:00</archiveUnder>
            </BlogPost>
            <BlogPost id="1203" parentID="1081" level="5" writerID="0" creatorID="0" nodeType="1087" template="1089" sortOrder="13" createDate="2010-10-12T12:13:05" updateDate="2010-10-12T12:13:27" nodeName="inceptos himenaeos" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1079,1081,1203" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
                <archiveUnder>2010-05-26T00:00:00</archiveUnder>
            </BlogPost>
            <BlogPost id="1204" parentID="1081" level="5" writerID="0" creatorID="0" nodeType="1087" template="1089" sortOrder="14" createDate="2010-10-12T12:13:36" updateDate="2010-10-12T12:13:56" nodeName="pharetra" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1079,1081,1204" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
                <archiveUnder>2010-06-11T00:00:00</archiveUnder>
            </BlogPost>
            <BlogPost id="1205" parentID="1081" level="5" writerID="0" creatorID="0" nodeType="1087" template="1089" sortOrder="15" createDate="2010-10-12T12:14:06" updateDate="2010-10-12T12:14:41" nodeName="Fusce augue" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1079,1081,1205" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
                <archiveUnder>2010-07-08T00:00:00</archiveUnder>
            </BlogPost>
            <BlogPost id="1206" parentID="1081" level="5" writerID="0" creatorID="0" nodeType="1087" template="1089" sortOrder="16" createDate="2010-10-12T12:14:52" updateDate="2010-10-12T12:15:19" nodeName="pharetra et fermentum" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1079,1081,1206" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
                <archiveUnder>2010-08-09T00:00:00</archiveUnder>
            </BlogPost>
            <BlogPost id="1207" parentID="1081" level="5" writerID="0" creatorID="0" nodeType="1087" template="1089" sortOrder="17" createDate="2010-10-12T12:15:31" updateDate="2010-10-12T12:15:51" nodeName="Fusce augue purus" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1079,1081,1207" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
                <archiveUnder>2010-09-14T00:00:00</archiveUnder>
            </BlogPost>
            <BlogPost id="1208" parentID="1081" level="5" writerID="0" creatorID="0" nodeType="1087" template="1089" sortOrder="18" createDate="2010-10-12T12:16:25" updateDate="2010-10-12T12:16:45" nodeName="Class aptent taciti" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1079,1081,1208" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
                <archiveUnder>2010-06-04T00:00:00</archiveUnder>
            </BlogPost>
            <BlogPost id="1209" parentID="1081" level="5" writerID="0" creatorID="0" nodeType="1087" template="1089" sortOrder="19" createDate="2010-10-12T12:17:01" updateDate="2010-10-12T12:17:29" nodeName="Class aptent" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1079,1081,1209" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
                <archiveUnder>2010-06-21T00:00:00</archiveUnder>
            </BlogPost>
        </Room>
        <Room id="1082" parentID="1079" level="4" writerID="0" creatorID="0" nodeType="1077" template="0" sortOrder="2" createDate="2010-09-27T14:12:33" updateDate="2010-10-07T14:43:09" nodeName="Test Blog" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1079,1082" isDoc="">
            <BlogPost id="1182" parentID="1082" level="5" writerID="0" creatorID="0" nodeType="1087" template="1089" sortOrder="1" createDate="2010-10-08T17:51:19" updateDate="2010-10-08T17:51:58" nodeName="Test Blog" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1079,1082,1182" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
            </BlogPost>
        </Room>
        <Room id="1083" parentID="1079" level="4" writerID="0" creatorID="0" nodeType="1077" template="1089" sortOrder="3" createDate="2010-09-27T14:12:40" updateDate="2010-10-07T14:49:48" nodeName="Test Blog" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1079,1083" isDoc="">
            <BlogPost id="1183" parentID="1083" level="5" writerID="0" creatorID="0" nodeType="1087" template="1089" sortOrder="1" createDate="2010-10-08T17:52:22" updateDate="2010-10-08T17:52:39" nodeName="Test Blog" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1079,1083,1183" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
            </BlogPost>
        </Room>
    </BlogCentre>
    <BlogCentre id="1080" parentID="1078" level="3" writerID="0" creatorID="0" nodeType="1075" template="1076" sortOrder="2" createDate="2010-09-27T14:11:55" updateDate="2010-10-07T14:43:23" nodeName="Blog Centre 2" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1080" isDoc="">
        <Room id="1084" parentID="1080" level="4" writerID="0" creatorID="0" nodeType="1077" template="0" sortOrder="1" createDate="2010-09-27T14:12:45" updateDate="2010-10-07T14:43:17" nodeName="Room 1" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1080,1084" isDoc="">
            <BlogPost id="1184" parentID="1084" level="5" writerID="0" creatorID="0" nodeType="1087" template="1089" sortOrder="1" createDate="2010-10-08T17:53:05" updateDate="2010-10-08T17:53:29" nodeName="Blog Post 3" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1080,1084,1184" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
            </BlogPost>
        </Room>
        <Room id="1085" parentID="1080" level="4" writerID="0" creatorID="0" nodeType="1077" template="0" sortOrder="2" createDate="2010-09-27T14:12:50" updateDate="2010-10-07T14:43:19" nodeName="Room 2" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1080,1085" isDoc="">
            <BlogPost id="1185" parentID="1085" level="5" writerID="0" creatorID="0" nodeType="1087" template="1089" sortOrder="1" createDate="2010-10-08T17:53:51" updateDate="2010-10-08T17:54:15" nodeName="Blog Post 109" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1080,1085,1185" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
            </BlogPost>
        </Room>
        <Room id="1086" parentID="1080" level="4" writerID="0" creatorID="0" nodeType="1077" template="1089" sortOrder="3" createDate="2010-09-27T14:12:55" updateDate="2010-10-07T14:50:39" nodeName="Room 3" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1080,1086" isDoc="">
            <BlogPost id="1186" parentID="1086" level="5" writerID="0" creatorID="0" nodeType="1087" template="1089" sortOrder="1" createDate="2010-10-08T17:54:28" updateDate="2010-10-08T17:54:51" nodeName="Blog Post 123" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1080,1086,1186" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
            </BlogPost>
        </Room>
    </BlogCentre>
</Blog>

In the Umbraco XSLT stylesheets, there is a parameter that gets passed for the current page.

<xsl:param name="currentPage" />

This will always be the parent node <Blog />, so we have to start form here.

You'll notice that there are intermediate nodes between <Blog /> and <BlogPost /> but we want to count the TOTAL number of BlogPosts in every <BlogCentre /> and <Room />.

To do this, I've been using

<xsl:for-each select="$currentPage/descendant::BlogPost" />

Which selects all the Blog Posts, regardless of Centre/Room.

Now the requirement I have is, to group each of these Blog Posts by Month and Year (including a Post count for each month). The date I'd like to group them by is the attribute createDate UNLESS there is a child node called <archiveUnder>some-date-here</archiveUnder>. To explain further

Update
I can easily do this part by checking if an attribute is blank, so the solution can omit this part if need-be.

<BlogPost createDate="2010-10-08T17:52:22">
    <!-- no archiveUnder -->
</BlogPost>

^ Use create Date

<BlogPost createDate="2010-10-08T17:52:22">
    <archiveUnder>2010-10-08T17:51:19</archiveUnder>
</BlogPost>

^ Use archiveUnder

Finally, here's an example of the expected output.

<ul>
    <li>
        <h3>2010</h3>
        <ul>
            <li>September (4)</li>
            <li>August (2)</li>
            <li>June (5)</li> <!-- No July because there are no posts -->
        </ul>
    </li>
    <li>
        <h3>2009</h3>
        <ul>
            <li>April (4)</li>
            <li>March (2)</li>
            <li>January (5)</li> <!-- No February because there are no posts -->
        </ul>
    </li>
</ul>
+2  A: 

As described by Jeni Tennison this would be a two-step method:

  1. Identify the months with blog posts.
  2. Get all the posts for a particular month.

We can get the first part using the following XPath expression:

BlogPost[not (substring(@createDate, 1, 7) 
    = substring(preceding-sibling::*[1]/@createDate, 1, 7))]

Then, for part two, we need to count the posts using the count() function:

BlogPost[not (substring(@createDate, 1, 7) 
    = substring(preceding-sibling::*[1]/@createDate, 1, 7))]

In our XSLT, we can use the expressions as follows:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="Room">
    <ul>
      <xsl:for-each select="BlogPost[not (substring(@createDate, 1, 7) = substring(preceding-sibling::*[1]/@createDate, 1, 7))]">
        <xsl:sort select="@createDate" order="descending"/>
        <li>
          <xsl:value-of select="substring(@createDate, 1, 7)"/>
          <xsl:text>(</xsl:text>
          <xsl:value-of select="count(//BlogPost[substring(@createDate, 1, 7) = substring(current()/@createDate, 1, 7)]) "/>
          <xsl:text>)</xsl:text>
        </li>
      </xsl:for-each>
    </ul>
  </xsl:template>

</xsl:stylesheet>

The stylesheet above simply works month-based and doesn't consider multiple years. To support years, you can add an additional step to get the unique years first:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="Room">
    <ul>
      <xsl:for-each select="BlogPost[not (substring(@createDate, 1, 4) = substring(preceding-sibling::*[1]/@createDate, 1, 4))]">
        <xsl:sort select="@createDate" order="descending"/>
        <li>
          <xsl:value-of select="substring(@createDate, 1, 4)"/>
          <ul>
            <xsl:for-each select="//BlogPost[substring(@createDate, 1, 4) = substring(current()/@createDate, 1, 4) and not (substring(@createDate, 1, 7) = substring(preceding-sibling::*[1]/@createDate, 1, 7))]">
              <xsl:sort select="@createDate" order="descending"/>
              <li>
                <xsl:value-of select="substring(@createDate, 1, 7)"/>
                <xsl:text>(</xsl:text>
                <xsl:value-of select="count(//BlogPost[substring(@createDate, 1, 7) = substring(current()/@createDate, 1, 7)]) "/>
                <xsl:text>)</xsl:text>
              </li>
            </xsl:for-each>
          </ul>
        </li>
      </xsl:for-each>
    </ul>
  </xsl:template>

</xsl:stylesheet>
0xA3
@0xA3 - this looks very promising. I'm just creating some test cases to make sure it's bulletproof.
Marko
@0xA3, I've attempted to use your code but I was getting a very weird output. See my updated question for more information
Marko
+3  A: 

This transformation (141 lines but formatted for readability):

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:m="my:months" exclude-result-prefixes="m" >
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:param name="currentPage" select="/*"/>

 <m:months>
   <m>January</m>
   <m>February</m>
   <m>March</m>
   <m>April</m>
   <m>May</m>
   <m>June</m>
   <m>July</m>
   <m>August</m>
   <m>September</m>
   <m>October</m>
   <m>November</m>
   <m>December</m>
 </m:months>

 <xsl:variable name="vMonthNames" select=
  "document('')/*/m:months/*"/>

 <xsl:key name="kPostsByYear" match="BlogPost"
  use="substring-before(
                    concat(archiveUnder,
                           @createDate[not(archiveUnder)]
                           ),
                    '-'
                        )"/>

 <xsl:key name="kPostsByYearMonth" match="BlogPost"
  use="substring(
                 concat(archiveUnder,
                        @createDate[not(archiveUnder)]
                        ),
                 1,7
                 )"/>

 <xsl:template match="/">
   <ul>
    <xsl:apply-templates mode="year" select=
     "$currentPage/*/*/BlogPost
          [generate-id()
          =
           generate-id(key('kPostsByYear',
                       substring-before(
                       concat(archiveUnder,
                              @createDate[not(archiveUnder)]
                              ),
                              '-'
                                         )
                            )[1]
                       )
              ]
     ">
       <xsl:sort order="descending" select=
        "substring-before(
                    concat(archiveUnder,
                           @createDate[not(archiveUnder)]
                           ),

                           '-'
                          )
        "/>
   </xsl:apply-templates>
  </ul>
 </xsl:template>

 <xsl:template match="BlogPost" mode="year">
  <xsl:variable name="vYear" select=
    "substring-before(
                     concat(archiveUnder,
                            @createDate[not(archiveUnder)]
                            ),

                      '-')
    "/>
  <xsl:variable name="vyearBlogs"
                select="key('kPostsByYear',$vYear)"/>
  <li>
    <h3><xsl:value-of select="$vYear"/></h3>
    <ul>
      <xsl:apply-templates mode="month" select=
          "$vyearBlogs
             [generate-id()
             =
              generate-id(key('kPostsByYearMonth',
                          substring(
                        concat(archiveUnder,
                               @createDate[not(archiveUnder)]
                               ),

                        1,7
                                    )
                              )[1]
                          )
              ]
          ">
         <xsl:sort order="descending" select=
            "substring(
                 concat(archiveUnder,
                        @createDate[not(archiveUnder)]
                        ),

                 6,2)"
         />
      </xsl:apply-templates>
   </ul>
  </li>
 </xsl:template>

 <xsl:template match="BlogPost" mode="month">
  <xsl:variable name="vMonth" select=
   "substring(
        concat(archiveUnder,
               @createDate[not(archiveUnder)]
               ),

        6,2)"/>

  <xsl:variable name="vmonthsBlogs" select=
    "key('kPostsByYearMonth',
         substring(
              concat(archiveUnder,
                     @createDate[not(archiveUnder)]
                     ),

              1,7)
         )"/>
  <li><xsl:value-of select=
        "concat($vMonthNames[position()=$vMonth],
                ' (',
                count($vmonthsBlogs),
                ')'
                )"/>
  </li>
 </xsl:template>
</xsl:stylesheet>

when applied on the provided sample XML document (we are accessing every node off the $currentPage <xsl:param> as this will be in the real Umbraco case), formatted for readability and the createDate attribute of every BlogPost moved on the firs line after the element name:

<Blog id="1078" parentID="1049" level="2" writerID="0" creatorID="0" nodeType="1073" template="1089" sortOrder="7" createDate="2010-09-27T14:11:04" updateDate="2010-10-12T16:59:12" nodeName="Blog" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078" isDoc="">
    <newPageTitle>The Lorem Ipsum Blog</newPageTitle>
    <BlogCentre id="1079" parentID="1078" level="3" writerID="0" creatorID="0" nodeType="1075" template="1076" sortOrder="1" createDate="2010-09-27T14:11:49" updateDate="2010-10-07T14:43:13" nodeName="Blog Centre 1" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1079" isDoc="">
        <Room id="1081" parentID="1079" level="4" writerID="0" creatorID="0" nodeType="1077" template="0" sortOrder="1" createDate="2010-09-27T14:12:26" updateDate="2010-10-07T14:43:06" nodeName="Room 10" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1079,1081" isDoc="">
            <BlogPost id="1175" parentID="1081" level="5"
            createDate="2010-10-07T14:51:48"
            writerID="0" creatorID="0" nodeType="1087"
            template="1192" sortOrder="1"
            updateDate="2010-10-12T21:30:53"
            nodeName="The first ever Blog post"
            writerName="Administrator"
            creatorName="Administrator"
            path="-1,1049,1078,1079,1081,1175" isDoc="">
                <topicTitle>The first ever blog</topicTitle>
                <archiveUnder/>
            </BlogPost>
            <BlogPost id="1180" parentID="1081"
             createDate="2010-10-08T15:52:20"
             level="5" writerID="0" creatorID="3"
             nodeType="1087" template="1089"
             sortOrder="2"
             updateDate="2010-10-12T16:57:00" nodeName="asdasd"
             writerName="Administrator" creatorName="ZX"
             path="-1,1049,1078,1079,1081,1180" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
            </BlogPost>
            <BlogPost id="1181" parentID="1081" level="5"
             createDate="2010-10-08T17:50:19"
             writerID="0" creatorID="0" nodeType="1087"
             template="1089" sortOrder="3"
             updateDate="2010-10-12T11:40:37"
             nodeName="condimentum"
             writerName="Administrator"
             creatorName="Administrator"
             path="-1,1049,1078,1079,1081,1181" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
                <archiveUnder>2010-09-01T00:00:00</archiveUnder>
            </BlogPost>
            <BlogPost id="1194" parentID="1081" level="5"
            createDate="2010-10-12T11:41:50"
            writerID="0" creatorID="0" nodeType="1087"
            template="1089" sortOrder="4"
            updateDate="2010-10-12T11:42:37"
            nodeName="Nam augue" writerName="Administrator"
            creatorName="Administrator"
            path="-1,1049,1078,1079,1081,1194" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
                <archiveUnder>2010-08-05T00:00:00</archiveUnder>
            </BlogPost>
            <BlogPost id="1195" parentID="1081" level="5"
            createDate="2010-10-12T11:42:15"
            writerID="0" creatorID="0" nodeType="1087"
            template="1089" sortOrder="5"
            updateDate="2010-10-12T11:42:25"
            nodeName="consequat nunc"
            writerName="Administrator"
            creatorName="Administrator"
            path="-1,1049,1078,1079,1081,1195" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
                <archiveUnder>2010-08-12T00:00:00</archiveUnder>
            </BlogPost>
            <BlogPost id="1196" parentID="1081" level="5"
            createDate="2010-10-12T12:05:57"
            writerID="0" creatorID="0" nodeType="1087"
            template="1089" sortOrder="6"
            updateDate="2010-10-12T12:08:40"
            nodeName="cursus congue"
            writerName="Administrator"
            creatorName="Administrator"
            path="-1,1049,1078,1079,1081,1196" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
                <archiveUnder>2009-10-22T00:00:00</archiveUnder>
            </BlogPost>
            <BlogPost id="1197" parentID="1081" level="5"
             createDate="2010-10-12T12:08:54"
             writerID="0" creatorID="0" nodeType="1087"
             template="1089" sortOrder="7"
             updateDate="2010-10-12T12:09:24"
             nodeName="inceptos" writerName="Administrator"
             creatorName="Administrator"
             path="-1,1049,1078,1079,1081,1197" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
                <archiveUnder>2009-11-19T00:00:00</archiveUnder>
            </BlogPost>
            <BlogPost id="1198" parentID="1081" level="5"
            createDate="2010-10-12T12:09:45"
            writerID="0" creatorID="0" nodeType="1087"
            template="1089" sortOrder="8"
            updateDate="2010-10-12T12:10:13"
            nodeName="inceptos himenaeos"
            writerName="Administrator"
            creatorName="Administrator"
            path="-1,1049,1078,1079,1081,1198" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
                <archiveUnder>2009-12-16T00:00:00</archiveUnder>
            </BlogPost>
            <BlogPost id="1199" parentID="1081" level="5"
             createDate="2010-10-12T12:10:29"
             writerID="0" creatorID="0" nodeType="1087"
             template="1089" sortOrder="9"
             updateDate="2010-10-12T12:10:56"
             nodeName="consequat" writerName="Administrator"
             creatorName="Administrator"
             path="-1,1049,1078,1079,1081,1199" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
                <archiveUnder>2010-01-13T00:00:00</archiveUnder>
            </BlogPost>
            <BlogPost id="1200" parentID="1081" level="5"
            createDate="2010-10-12T12:11:08"
            writerID="0" creatorID="0" nodeType="1087"
            template="1089" sortOrder="10"
            updateDate="2010-10-12T12:11:35"
            nodeName="himenaeos" writerName="Administrator"
            creatorName="Administrator"
            path="-1,1049,1078,1079,1081,1200" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
                <archiveUnder>2010-02-09T00:00:00</archiveUnder>
            </BlogPost>
            <BlogPost id="1201" parentID="1081" level="5"
             createDate="2010-10-12T12:11:45"
             writerID="0" creatorID="0" nodeType="1087"
             template="1089" sortOrder="11"
             updateDate="2010-10-12T12:12:35"
             nodeName="cursus congue" writerName="Administrator"
             creatorName="Administrator"
             path="-1,1049,1078,1079,1081,1201" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
                <archiveUnder>2010-04-22T00:00:00</archiveUnder>
            </BlogPost>
            <BlogPost id="1202" parentID="1081" level="5"
            createDate="2010-10-12T12:12:18"
            writerID="0" creatorID="0" nodeType="1087"
            template="1089" sortOrder="12"
            updateDate="2010-10-12T12:12:45" nodeName="pharetra"
            writerName="Administrator" creatorName="Administrator"
            path="-1,1049,1078,1079,1081,1202" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
                <archiveUnder>2010-03-09T00:00:00</archiveUnder>
            </BlogPost>
            <BlogPost id="1203" parentID="1081" level="5"
            createDate="2010-10-12T12:13:05"
            writerID="0" creatorID="0" nodeType="1087"
            template="1089" sortOrder="13"
            updateDate="2010-10-12T12:13:27"
            nodeName="inceptos himenaeos"
            writerName="Administrator"
            creatorName="Administrator"
            path="-1,1049,1078,1079,1081,1203" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
                <archiveUnder>2010-05-26T00:00:00</archiveUnder>
            </BlogPost>
            <BlogPost id="1204" parentID="1081" level="5"
            createDate="2010-10-12T12:13:36"
            writerID="0" creatorID="0" nodeType="1087"
            template="1089" sortOrder="14"
            updateDate="2010-10-12T12:13:56"
            nodeName="pharetra" writerName="Administrator"
            creatorName="Administrator"
            path="-1,1049,1078,1079,1081,1204" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
                <archiveUnder>2010-06-11T00:00:00</archiveUnder>
            </BlogPost>
            <BlogPost id="1205" parentID="1081" level="5"
            createDate="2010-10-12T12:14:06"
            writerID="0" creatorID="0" nodeType="1087"
            template="1089" sortOrder="15"
            updateDate="2010-10-12T12:14:41"
            nodeName="Fusce augue" writerName="Administrator"
            creatorName="Administrator"
            path="-1,1049,1078,1079,1081,1205" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
                <archiveUnder>2010-07-08T00:00:00</archiveUnder>
            </BlogPost>
            <BlogPost id="1206" parentID="1081" level="5"
            createDate="2010-10-12T12:14:52"
            writerID="0" creatorID="0" nodeType="1087"
            template="1089" sortOrder="16"
            updateDate="2010-10-12T12:15:19"
            nodeName="pharetra et fermentum"
            writerName="Administrator" creatorName="Administrator"
            path="-1,1049,1078,1079,1081,1206" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
                <archiveUnder>2010-08-09T00:00:00</archiveUnder>
            </BlogPost>
            <BlogPost id="1207" parentID="1081"
            createDate="2010-10-12T12:15:31"
            level="5" writerID="0" creatorID="0" nodeType="1087"
            template="1089" sortOrder="17"
            updateDate="2010-10-12T12:15:51"
            nodeName="Fusce augue purus" writerName="Administrator"
            creatorName="Administrator"
            path="-1,1049,1078,1079,1081,1207" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
                <archiveUnder>2010-09-14T00:00:00</archiveUnder>
            </BlogPost>
            <BlogPost id="1208" parentID="1081" level="5"
            createDate="2010-10-12T12:16:25"
            writerID="0" creatorID="0" nodeType="1087"
            template="1089" sortOrder="18"
            updateDate="2010-10-12T12:16:45"
            nodeName="Class aptent taciti" writerName="Administrator"
            creatorName="Administrator"
            path="-1,1049,1078,1079,1081,1208" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
                <archiveUnder>2010-06-04T00:00:00</archiveUnder>
            </BlogPost>
            <BlogPost id="1209" parentID="1081" level="5"
            createDate="2010-10-12T12:17:01"
            writerID="0" creatorID="0" nodeType="1087"
            template="1089" sortOrder="19"
            updateDate="2010-10-12T12:17:29" nodeName="Class aptent"
            writerName="Administrator" creatorName="Administrator"
            path="-1,1049,1078,1079,1081,1209" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
                <archiveUnder>2010-06-21T00:00:00</archiveUnder>
            </BlogPost>
        </Room>
        <Room id="1082" parentID="1079" level="4"
        createDate="2010-09-27T14:12:33"
        writerID="0" creatorID="0" nodeType="1077" template="0"
        sortOrder="2"
        updateDate="2010-10-07T14:43:09" nodeName="Test Blog"
        writerName="Administrator" creatorName="Administrator"
        path="-1,1049,1078,1079,1082" isDoc="">
            <BlogPost id="1182" parentID="1082" level="5" writerID="0" creatorID="0" nodeType="1087" template="1089" sortOrder="1" createDate="2010-10-08T17:51:19" updateDate="2010-10-08T17:51:58" nodeName="Test Blog" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1079,1082,1182" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
            </BlogPost>
        </Room>
        <Room id="1083" parentID="1079" level="4" writerID="0"
        createDate="2010-09-27T14:12:40"
        creatorID="0" nodeType="1077" template="1089" sortOrder="3"
        updateDate="2010-10-07T14:49:48" nodeName="Test Blog"
        writerName="Administrator" creatorName="Administrator"
        path="-1,1049,1078,1079,1083" isDoc="">
            <BlogPost id="1183" parentID="1083" level="5" writerID="0" creatorID="0" nodeType="1087" template="1089" sortOrder="1" createDate="2010-10-08T17:52:22" updateDate="2010-10-08T17:52:39" nodeName="Test Blog" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1079,1083,1183" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
            </BlogPost>
        </Room>
    </BlogCentre>
    <BlogCentre id="1080" parentID="1078" level="3" writerID="0"
    createDate="2010-09-27T14:11:55"
    creatorID="0" nodeType="1075" template="1076" sortOrder="2"
    updateDate="2010-10-07T14:43:23" nodeName="Blog Centre 2"
    writerName="Administrator" creatorName="Administrator"
    path="-1,1049,1078,1080" isDoc="">
        <Room id="1084" parentID="1080" level="4" writerID="0" creatorID="0" nodeType="1077" template="0" sortOrder="1" createDate="2010-09-27T14:12:45" updateDate="2010-10-07T14:43:17" nodeName="Room 1" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1080,1084" isDoc="">
            <BlogPost id="1184" parentID="1084" level="5" writerID="0"
            createDate="2010-10-08T17:53:05"
            creatorID="0" nodeType="1087" template="1089" sortOrder="1"
            updateDate="2010-10-08T17:53:29" nodeName="Blog Post 3"
            writerName="Administrator" creatorName="Administrator"
            path="-1,1049,1078,1080,1084,1184" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
            </BlogPost>
        </Room>
        <Room id="1085" parentID="1080" level="4" writerID="0"
        createDate="2010-09-27T14:12:50"
        creatorID="0" nodeType="1077" template="0" sortOrder="2"
        updateDate="2010-10-07T14:43:19" nodeName="Room 2"
        writerName="Administrator" creatorName="Administrator"
        path="-1,1049,1078,1080,1085" isDoc="">
            <BlogPost id="1185" parentID="1085" level="5" writerID="0"
            createDate="2010-10-08T17:53:51"
            creatorID="0" nodeType="1087" template="1089" sortOrder="1"
            updateDate="2010-10-08T17:54:15" nodeName="Blog Post 109"
            writerName="Administrator" creatorName="Administrator"
            path="-1,1049,1078,1080,1085,1185" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
            </BlogPost>
        </Room>
        <Room id="1086" parentID="1080" level="4" writerID="0" creatorID="0" nodeType="1077" template="1089" sortOrder="3" createDate="2010-09-27T14:12:55" updateDate="2010-10-07T14:50:39" nodeName="Room 3" writerName="Administrator" creatorName="Administrator" path="-1,1049,1078,1080,1086" isDoc="">
            <BlogPost id="1186" parentID="1086" level="5" writerID="0"
            createDate="2010-10-08T17:54:28"
            creatorID="0" nodeType="1087" template="1089" sortOrder="1"
            updateDate="2010-10-08T17:54:51"
            nodeName="Blog Post 123" writerName="Administrator"
            creatorName="Administrator"
            path="-1,1049,1078,1080,1086,1186" isDoc="">
                <topicTitle>Lorem Ipsum</topicTitle>
            </BlogPost>
        </Room>
    </BlogCentre>
</Blog>

produces the wanted, correct result:

<ul>
   <li>
      <h3>2010</h3>
      <ul>
         <li>October (7)</li>
         <li>September (2)</li>
         <li>August (3)</li>
         <li>July (1)</li>
         <li>June (3)</li>
         <li>May (1)</li>
         <li>April (1)</li>
         <li>March (1)</li>
         <li>February (1)</li>
         <li>January (1)</li>
      </ul>
   </li>
   <li>
      <h3>2009</h3>
      <ul>
         <li>December (1)</li>
         <li>November (1)</li>
         <li>October (1)</li>
      </ul>
   </li>
</ul>

Do note:

  1. Muenchian Grouping is used -- both for determining the different years and for determining the different months for each year.

  2. The date is chosen between the createDate attribute and the archiveUnder child using the expression:

    concat(archiveUnder, @createDate[not(archiveUnder)])

This concatenation only picks @createDate if archiveUnder is missing or empty.

.3. The transformation will produce the correct result even if the dates of the elements are unsorted.

Dimitre Novatchev
@Dimitre: +1 I've missed to order the results.
Alejandro
@Alejandro: Thanks. You must update your answer, adding the missing sorting. There are still 7 days until the end of the bounty period.
Dimitre Novatchev
Hi @Dimitre, I've deleted all my comments to ease things up a bit. I've just tried your code but it throws an error `Error parsing XSLT file: \xslt\blogArchive.xslt".` Usually umbraco does specify what the error is but in this case it doesn't. After inspecting the code, I noticed you're not using $currentPage anywhere. That's the source of the XML as mentioned above and it contains a nodeset starting from `<Blog>`.
Marko
I tried replacing this line `*/*/BlogPost` with `currentPage/descendant::BlogPost` but I get an error `For security reasons DTD is prohibited in this XML document. To enable DTD processing set the DtdProcessing property on XmlReaderSettings to Parse and pass the settings into XmlReader.Create method.` I found this article on the forums http://our.umbraco.org/forum/developers/xslt/3008-Namespaces-in-xslt and have tried replacing `xmlns:m="my:months"` with `xmlns:m="urn:months"` but to no avail. At this point I seriously don't know what to do. :/
Marko
@Marko-Ivanovski: Yes, I have changed the code slightly and now the nodes are accessed off the `$currentPage` `<xsl:param>`. Please, try the updated solution.
Dimitre Novatchev
@Dimitre, we're so close! I think the @CreateDate isn't being picked up because only the nodes that have `archiveUnder` are being grouped. The ones that don't sit as uncategorized, with the number of posts showing `(10)`. Is there an alternative way of doing `(@createDate|archiveUnder)`?
Marko
@Marko-Ivanovski: [only the nodes that have archiveUnder are being grouped] -- This is not true. There are a total of 24 `BlogPost` elements in the provided XML document. The sum of the counts in the output is exactly 24. Also, not all of the `BlogPost` elements have a `archiveUnder` child.
Dimitre Novatchev
@Marko-Ivanovski: You are probably applying the transformation on some XML document that doesn't have the properties, stated in the question. For example, if there is a `BlogPost` element that doesnt have a `createDate` attribute *and* also doesn't have an `archiveUnder` child, this `BlogPost` element will not be represented in the result. Other problems could arise, if the date format is different than the one shown in the question.
Dimitre Novatchev
Hi @Dimitre, I've just had another look at the file and the nodes that don't have an archive date have an empty node `<archiveUnder />`. I've checked the date formats and they're definitely the same. Further to that, all nodes have a `@CreateDate` :)
Marko
@Marko-Ivanovski: I see. The question is phrased in such a way that one believes that `archiveUnder` is present only in some `BlogPost` nodes. This is something new. Try replacing all occurencies of `(@createDate|archiveUnder)[last()]` with `concat(@createDate,archiveUnder)` . If this produces the wanted results, I will update my answer. It would also be good if you could update your question to state explicitly, that every `Blogpost` element has an `archiveUnder` child anf whenever this `archiveUnder` child is empty, the date should be taken from the `CreateDate` attribute.
Dimitre Novatchev
@Marko-Ivanovski: I updated the XML document and the solution to work with the new document structure you described in your last comment. Please, try.
Dimitre Novatchev
@Dimitre, when you reply to my comments use just @Marko, it doesn't seems to notify me when you're using a dash (-) inside my name. Anyway I tried the `concat(@createDate,archiveUnder)` which didn't actually work but `concat(archiveUnder,@createDate)` does seem to? I'm just running some tests, but I presume that since we're using substring, it will always match the first date even if there were 2 concatenated together? Could this really be the end of my problem? :)
Marko
@Marko: Look at the updated solution. You should use: `concat(archiveUnder, @createDate[not(archiveUnder)])`
Dimitre Novatchev
@Dimitre, congratulations. I believe you've nailed it! I will award you your well deserved bounty now, and if there are any further problems I'll start a new thread. Thanks a million dude!
Marko
@Marko: I am glad the solution is finally providing the expected results. This has been a nice experience working on a real-world problem. Thank you very much for providing this problem, Marko.
Dimitre Novatchev
@Dimitre, it definitely has been. I'm starting to like XSLT more and more. I've just added in one final condition in each match="BlogPost" and inside the `<match-templates />` that only selects nodes that the user has access to using `[umbraco.library:HasAccess(@id, @path) = 'true']`. It works like a charm and it's actually really fast! Gonna cache the results for at least a day anyway, so that's problem solved :) Thanks again!!
Marko
@MArko: Ypu are welcome. And yes, XSLT is a fascinating language.
Dimitre Novatchev
Oops! I've missed the last comments. But I think that `(@createDate|archiveUnder[node()])[last()]` could also work.
Alejandro
@Alejandro: No, because in XSLT 1.0 `<xsl:value-of>` always selects only the first node of a node-set.
Dimitre Novatchev
+2  A: 

This stylesheet:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:m="month"
 exclude-result-prefixes="m">
    <xsl:param name="currentPage" select="/Blog"/>
    <xsl:key name="kBlogPostByYear" match="BlogPost"
             use="substring((@createDate|archiveUnder)[last()],1,4)"/>
    <xsl:key name="kBlogPostByYearMonth" match="BlogPost"
             use="substring((@createDate|archiveUnder)[last()],1,7)"/>
    <m:month>January</m:month>
    <m:month>February</m:month>
    <m:month>March</m:month>
    <m:month>April</m:month>
    <m:month>May</m:month>
    <m:month>June</m:month>
    <m:month>July</m:month>
    <m:month>August</m:month>
    <m:month>September</m:month>
    <m:month>October</m:month>
    <m:month>November</m:month>
    <m:month>December</m:month>
    <xsl:variable name="vMonth" select="document('')/*/m:*"/>
    <xsl:template match="/">
        <ul>
            <xsl:apply-templates
                 select="$currentPage/*/*/BlogPost
                                 [count(.|key('kBlogPostByYear',
                                              substring((@createDate|
                                                         archiveUnder)
                                                         [last()],
                                                        1,
                                                        4))[1])=1]">
                <xsl:sort select="substring((@createDate|archiveUnder)
                                            [last()],
                                            1,4)" order="descending"/>
            </xsl:apply-templates>
        </ul>
    </xsl:template>
    <xsl:template match="BlogPost">
        <xsl:variable name="vYear" select="substring((@createDate|
                                                      archiveUnder)[last()],
                                                      1,
                                                      4)"/>
        <ul>
            <h3>
                <xsl:value-of select="$vYear"/>
            </h3>
            <ul>
                <xsl:apply-templates
                     select="$currentPage/*/*/BlogPost
                                         [generate-id() =
                                          generate-id(
                                             key('kBlogPostByYearMonth',
                                                 concat($vYear,'-',
                                                        substring(
                                                           (@createDate|
                                                            archiveUnder)
                                                                 [last()],
                                                           6,
                                                           2))))]"
                                     mode="month">
                    <xsl:sort select="substring((@createDate|archiveUnder)
                                                [last()],
                                                6,2)" order="descending"/>
                </xsl:apply-templates>
            </ul>
        </ul>
    </xsl:template>
        <xsl:template match="BlogPost" mode="month">
        <xsl:variable name="vDate"
                      select="(@createDate|archiveUnder)[last()]"/>
        <li>
            <xsl:value-of select="concat($vMonth
                                            [number(
                                               substring($vDate,
                                                         6,
                                                         2))],
                                         ' (',
                                         count(key('kBlogPostByYearMonth',
                                                   substring($vDate,1,7))),
                                         ')')"/>
        </li>
    </xsl:template>
</xsl:stylesheet>

Output:

<ul>
    <ul>
        <h3>2010</h3>
        <ul>
            <li>October (7)</li>
            <li>September (2)</li>
            <li>August (3)</li>
            <li>July (1)</li>
            <li>June (3)</li>
            <li>May (1)</li>
            <li>April (1)</li>
            <li>March (1)</li>
            <li>February (1)</li>
            <li>January (1)</li>
        </ul>
    </ul>
    <ul>
        <h3>2009</h3>
        <ul>
            <li>December (1)</li>
            <li>November (1)</li>
            <li>October (1)</li>
        </ul>
    </ul>
</ul>

Edit 3: Sorry, I've missed the sorting. Now added. Also, minor refactor with a $currentPage param.

Alejandro
@Alejandro - does this take into consideration the year as well? Also I don't need the second part that lists the content, just the `<ul></ul>` section.
Marko
@Marko Ivanovski: You wrote: *does this take into consideration the year as well?* **Yes**, the grouping key is year-month (first 7 digits of date). You wrote: *Also I don't need the second part*. Well, it's for showing you the use of keys for selecting.
Alejandro
@Alejandro, appologies for the confusion, please see my updated question, hopefully it makes more sense.
Marko