It's not entirely clear from the bitmap in your question whether you intially have a DataTable or an XDocument. So let's assume you have an XDocument, and you would like to group the child rows of the root element by the values of their first four columns, with the remaining values collected under a sequence of elements named <BID_INTERVALS>.
This can be accomplished using the following extension method:
public static partial class XNodeExtensions
{
public static XElement CopyAndGroupChildrenByColumns(this XElement root, Func<XName, int, bool> columnFilter, XName groupName) =>
new XElement(root.Name,
root.Attributes(),
root.Elements()
.Select((row) => (row, key : row.Elements().Where((e, i) => columnFilter(e.Name, i)).Select(e => (e.Name, e.Value)).ToHashSet()))
.GroupByKeyAndSet(pair => pair.row.Name, pair => pair.key)
.Select(g => new XElement(g.Key.Key,
g.Key.Set.Select(p => new XElement(p.Name, p.Value)).Concat(g.Select(i => new XElement(groupName, i.row.Elements().Where((e, i) => !columnFilter(e.Name, i))))))));
public static IEnumerable<IGrouping<(TKey Key, HashSet<TItem> Set), TSource>> GroupByKeyAndSet<TSource, TKey, TItem>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, HashSet<TItem>> setSelector) =>
Enumerable.GroupBy(source, (i) => (keySelector(i), setSelector(i)), new CombinedComparer<TKey, HashSet<TItem>>(null, HashSet<TItem>.CreateSetComparer()));
}
public class CombinedComparer<T1, T2> : IEqualityComparer<ValueTuple<T1, T2>>
{
readonly IEqualityComparer<T1> comparer1;
readonly IEqualityComparer<T2> comparer2;
public CombinedComparer(IEqualityComparer<T1> comparer1, IEqualityComparer<T2> comparer2) => (this.comparer1, this.comparer2) = (comparer1 ?? EqualityComparer<T1>.Default, comparer2 ?? EqualityComparer<T2>.Default);
public bool Equals(ValueTuple<T1, T2> x, ValueTuple<T1, T2> y) => comparer1.Equals(x.Item1, y.Item1) && comparer2.Equals(x.Item2, y.Item2);
public int GetHashCode(ValueTuple<T1, T2> obj) => HashCode.Combine(comparer1.GetHashCode(obj.Item1), comparer2.GetHashCode(obj.Item2));
}
Then, given some XDocument doc, you can do:
// Group by the first four columns with all remaining elements collected under a <BID_INTERVALS> sequence of elements:
XName groupName = doc.Root.Name.Namespace + "BID_INTERVALS";
var grouped = doc.Root.CopyAndGroupChildrenByColumns((n, i) => (i < 4), groupName);
var newDoc = new XDocument(grouped);
If, on the other hand, you have a DataTable dt not an XDocument, you can convert the table to an XDocument directly using the following extension method:
public static partial class XNodeExtensions
{
public static XDocument ToXDocument(this DataTable dt, XmlWriteMode mode = XmlWriteMode.IgnoreSchema)
{
var doc = new XDocument();
using (var writer = doc.CreateWriter())
dt.WriteXml(writer, mode);
return doc;
}
}
And then do:
var doc = dt.ToXDocument(XmlWriteMode.IgnoreSchema);
Demo fiddle here.