I'm afraid that neither Group By (because it is an aggregate function) or Hierarchical transformations (because your items don't depend on item level, class name and differ only in a value in a single column) will do what you need in this case.
To get this working you can use Repeater web part along with Order by condition on the Year column.
Once your items are ordered, you then want to display the Year ONLY if the year is different then it was in previous items. This is the tricky part because there is no easy way to access previous/next or any other item inside a transformation. Luckily though it is possible in both ASCX and TEXT/XML transformations via some tricks.
With Text/XML transformation you will need to create a Custom macro method that will be able to store the value in throughout the life of current request for next item.
I've successfully used following macro for this purpose:
using System;
using CMS.MacroEngine;
using CMS.Helpers;
using CMS;
// Makes all methods in the 'CustomMacroMethods' container class available for string objects
[assembly: RegisterExtension(typeof(CustomMacroMethods), typeof(string))]
// Registers methods from the 'CustomMacroMethods' container into the "String" macro namespace
[assembly: RegisterExtension(typeof(CustomMacroMethods), typeof(StringNamespace))]
public class CustomMacroMethods : MacroMethodContainer
{
[MacroMethod(typeof(string), "Saves given value in memory and returns previously saved value", 1)]
[MacroMethodParam(1, "value", typeof(string), "Value to be saved")]
public static object SaveValueInMemory(EvaluationContext context, params object[] parameters)
{
switch (parameters.Length)
{
case 1:
string stockName = "SaveValueInMemory";
// get current value
string currentValue = ValidationHelper.GetString(RequestStockHelper.GetItem(stockName), null);
// set new value
RequestStockHelper.Add(stockName, ValidationHelper.GetString(parameters[0], ""));
// return current value
return currentValue;
default:
// No other overloads are supported
throw new NotSupportedException();
}
}
}
Then inside the Text/XML transformation you need to store and get the value from the Request storage and compare it. The transformation could look like:
{% if(SaveValueInMemory(Year) != Year){ %}
<h1>Year: {% Year%} </h1>
{% } |(identity)GlobalAdministrator%}</p>
On my end the result looks like:
Year: 2016
News article: Apple iPad 2 In Stock
Year: 2015
News article: Company Growth Exceeds Expectations
News article: Community Website Section
If you are using ASCX transformation you can use following code to get the Year column from previous item and generate same output using:
<%# DataItemIndex == 0 ? "<h1>" + Eval("Month") + "</h1>" : string.Empty %>
<%# ((DataItemIndex > 0) ? ((System.Data.DataView)((BasicRepeater)Parent.Parent).DataSource)[DataItemIndex-1]["Month"].ToString() != Eval("Month").ToString() ? "<h1>" + Eval("Month") + "</h1>" : string.Empty : string.Empty) %>
<p>News article: <%# Eval("DocumentName") %></p>
All you need to do with this is again to compare it with current value and display your headline only if it differs from previous value. That is why the order by is extremely important in this scenario.
Another option that I haven't mentioned is by using the Nested repeaters but due to performance reasons I would strongly advised not to do that.