簡體   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