繁体   English   中英

按多个节点对 XDocument 进行分组(动态)

[英]group XDocument by multiple nodes (dynamic)

我有以下数据作为 DataTable 进来。 如果我直接将它转换为 XML,我会得到很好的 xdocument 对象。

在此处输入图像描述

但是问题是我需要按前 4 列对其进行分组,以便 XML 如下所示。 我知道数据表中只有三个节点“Segment”、“Price”和“Qty”其余列可能是动态的,不能使用硬编码名称(上述 3 除外)

<ROOT>
<ROW>
    <Col1>CESLP</Col1>
    <Col2>MRP</Col2>
    <Col3>372</Col3>
    <Date>20040101</Date>
    <BID_INTERVALS>
        <SEGMENT>1</SEGMENT>
        <Price>10</Price>
        <QTY>5</QTY>
    </BID_INTERVALS>
    <BID_INTERVALS>
        <SEGMENT>2</SEGMENT>
        <Price>15</Price>
        <QTY>6</QTY>
    </BID_INTERVALS>
</ROW>
<ROW>
    <Col1>CESLP</Col1>
    <Col2>MRP</Col2>
    <Col3>372</Col3>
    <Date>20040102</Date>
    <BID_INTERVALS>
        <SEGMENT>1</SEGMENT>
        <Price>11</Price>
        <QTY>5</QTY>
    </BID_INTERVALS>
    <BID_INTERVALS>
        <SEGMENT>2</SEGMENT>
        <Price>14.5</Price>
        <QTY>6</QTY>
    </BID_INTERVALS>
</ROW>

有什么解决办法吗? 我被困了很长一段时间,通过'except'尝试了xdocument group,但对我没有用。

编辑1:

我正在使用下面的代码对记录进行分组(使用此处的解决方案

dataTable.AsEnumerable()
                .GroupBy(r => new NTuple<object>(from column in colNames select r[column]))
                .Select(g => g.CopyToDataTable()).ToList();

从您的问题中的位图中,您最初是否拥有DataTableXDocument并不完全清楚。 因此,假设您有一个XDocument ,并且您希望根据前四列的值对根元素的子行进行分组,其余值收集在名为<BID_INTERVALS>的元素序列下。

这可以使用以下扩展方法来完成:

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));
}

然后,给定一些XDocument doc ,您可以执行以下操作:

// 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);

另一方面,如果您有一个DataTable dt而不是XDocument ,则可以使用以下扩展方法直接将表转换为XDocument

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;
    }
}

然后做:

var doc = dt.ToXDocument(XmlWriteMode.IgnoreSchema);

演示小提琴在这里

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM