簡體   English   中英

如何通過Linq-to-XML查詢合並組的結果?

[英]How can I merge the results of a group by Linq-to-XML query?

我正在嘗試構造一個執行以下步驟的Linq-to-XML查詢:

  1. 將XDocument中的所有后代節點分組
  2. 匯總每個組中的不同項
  3. 按照我選擇的順序,用聚合的項目替換每個組中最后一個項目的父項中的元素
  4. 刪除每個組中的所有原始項目

到目前為止,我具有使用以下代碼的前兩個步驟。 請注意,MyGroupByKeyFunction的編寫方式可確保(除其他事項外)每個組中的所有元素都具有相同的深度(這就是orderby起作用的原因)。

var groups =
    from e in doc.Root.Descendants()
    group e by MyGroupByKeyFunction(e) into g
    orderby g.First().Ancestors().Count() descending
    select new {
        agg = g.Aggregate(new List<XElement>(), (list, el) => {
            list.Add(el);
            return list;
        }).Distinct(new MyCustomXElementEqualityComparer()),
        items = g,
        target = g.Last().Parent
    };

最后兩個步驟是我陷入困境的地方。 我嘗試了以下方法,但是它並沒有按照我想要的方式工作。

foreach (var group in groups)
{
    group.items.Remove();
    foreach (var item in group.merge)
    {
        group.target.Add(item);
    }
 }

group.items中的元素已成功刪除並填充了目標,但我也希望在對group.items.Remove()的調用導致清空父元素的情況下,刪除group.items中元素的父元素。 因此,我嘗試用以下命令替換該行:

foreach (var delete in group.items)
{
    if (delete.Parent.Elements().Count() == 1)
        delete.Parent.Remove();

    else
        delete.Remove();
}

問題在於,此循環結果的連續迭代會導致NullReferenceException,因為父元素可能作為項目存在於原始查詢結果的另一個組中! 當然,這會導致delete.Parent為null,因為它先前已與XML樹分離。

我該如何解決這個問題?

更新資料

根據Falanor的建議,我嘗試將代碼修改為以下內容。 但是,這導致XDocument的最終結果僅包含根元素。 我不知道為什么會這樣。 有什么想法或更好的解決方案嗎?

HashSet<XElement> removed = new HashSet<XElement>();
foreach (var group in groups)
{
    removed.UnionWith(group.items.Select(el => el.Parent).Where(el => !el.Parent.Equals(group.target)));
    group.items.Remove();
    foreach (var item in group.merge)
    {
        if (!removed.Contains(item))
            group.target.Add(item);
    }
}

removed.Where(el => el.Parent != null).Remove();

事實證明,Falanor的想法是正確的,我在編寫導致其無法使用的解決方案的方式時出現了一個小錯誤。 對UnionWith的方法調用應該是:

removed.UnionWith(group.items.Select(el => el.Parent).Where(el => !el.Equals(group.target)));

注意錯誤在where子句中。

此外,對於任何有興趣的人,我意識到我可以通過在初始查詢中添加以下“ where”子句(恰好在最終的“ select”語句之前)來大大減少代碼的執行時間:

where g.Select(p => p.Parent).Distinct().Count() > 1

這將導致查詢僅返回屬於不同父級的元素的分組。 只是為了透視起見,我針對我的代碼的XML文件返回了200,000多個分組。 加上附加的“ where”子句,分組數量下降到約150個! 最終結果是相同的。

也許刪除父母(以及孩子們)這樣做?

foreach (var group in groups)
{
if(group.Parent.Elements().Count() == 1)
group.Parent.Remove();
else
group.items.Remove();
foreach (var item in group.merge)
{
    group.target.Add(item);
}
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM