Linq XML后代在枚举时丢失 [英] Linq XML descendants being lost on enumeration

查看:49
本文介绍了Linq XML后代在枚举时丢失的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个这样的XML文档

I have an XML document like this

<root>
  <item id="1" creator="me">
    <childA>1</childA>
    <childB>2</childB>
  </item>
  <item id="2" creator="me">
    <childA>1</childA>
    <childB>3</childB>
    <childB>4</childB>
  </item>
</root>

我正在尝试查找重复的项目,然后使用类似的逻辑再次为重复的项目重复子项目

I'm trying to find duplicate items, then again duplicate child items for the duplicate items with logic like this

XDocument XmlRoot //whatever...you get the point

// Get item nodes
var items = XmlRoot.Descendants("item");

// Find duplicate items keys using creator attribute
var duplicateItemKeys = items.GroupBy(x => x.Attribute("creator").Value)
.Where(g => g.Count() > 1)
.Select(g => g.Key);

foreach(var duplicateItemKey in duplicateItemKeys)
{
  // Get the duplicate item XML elements using the duplicate keys
  var duplicateItems = items.Where(x => x.Attribute("creator").Value == duplicateToucheKey)
      .OrderBy(xelement => xelement.Attribute("CreatedOn").Value);
}

这有效,但是稍后我尝试使用重复项时出现问题.每当枚举时(例如在foreachplicateItems中),第一个项目都会松散其子级的上下文.第二个很好.

This works, however there is a problem later when I try to use duplicateItems. Any time it enumerates (like in a foreach duplicateItems) the first item looses the context of it's children. The second one is just fine.

例如,稍后在代码中我说

So for example, later in code I say

var allItemB = new List<XElement>();
foreach (duplicateItem in duplicateItems) 
{
  allItemB.AddRange(duplicateItem.Descendants("childB"));
}

我希望"allItemB"在第一遍包含2,然后在第二遍包含234.最终发生的事情是它只包含34个,因为一旦对plicateItems数组进行了枚举,第一个XElement就会失去它的孩子.

I expect "allItemB" to contain 2 on the first pass, then 234 on the second. What ends up happening is that it only contains 34 because once the duplicateItems array is enumerated the first XElement looses it's children.

有人知道如何解决此问题吗?

Does anyone know how to fix this?

推荐答案

如果我正确理解了您的问题,则希望allItemB具有3个元素-allItemB [0]是值为2的XElement childB,[1]为3而[2]为4?

If I understand your question correctly, you want allItemB to have 3 elements - allItemB[0] is the XElement childB with value 2, [1] to be 3 and [2] to be 4?

如果是这样,问题就出在您声明重复项.您的代码相同甚至无法编译,因为变量的范围仅限于第一个foreach循环,因此在第二个循环中不可用.

If so, the problem is where you are declaring duplicateItems. Your code same doesn't even compile, as the variable's scope is limited to the first foreach loop, and thus not available at the second.

我的代码获得以上结果:

My code to get the above result:

XDocument XmlRoot = XDocument.Load( "C:\\somefile.xml" );

// Get item nodes
var items = XmlRoot.Descendants("item");

// Find duplicate items keys using creator attribute
var duplicateItemKeys = items.GroupBy(x => x.Attribute("creator").Value)
     .Where(g => g.Count() > 1)
     .Select(g => g.Key);

IEnumerable<XElement> duplicateItems = new List<XElement>();
foreach(var duplicateItemKey in duplicateItemKeys)
{
     // Get the duplicate item XML elements using the duplicate keys
     duplicateItems = items.Where(x => x.Attribute("creator").Value == duplicateItemKey)
          .OrderBy(xelement => xelement.Attribute("id").Value);
 }

 var allItemB = new List<XElement>();
 foreach (var duplicateItem in duplicateItems) 
 {
      allItemB.AddRange(duplicateItem.Descendants("childB"));
 }

忘了提到我在第一个foreach循环中更改了OrderBy,因为示例xml文件没有CreatedOn属性.

forgot to mention that I changed the OrderBy in the first foreach loop because the sample xml file didn't have the CreatedOn attribute.

如果需要,您可以使用更多的Linq并完全丢弃foreach循环,如下所示:

And if you want, you can use a little more Linq and drop the foreach loops entirely, like so:

XDocument XmlRoot = XDocument.Load( "C:\\somefile.xml" );

// Get item nodes
var items = XmlRoot.Descendants("item");

// Find duplicate items keys using creator attribute
var duplicateItemKeys = items.GroupBy(x => x.Attribute("creator").Value)
     .Where(g => g.Count() > 1)
     .Select(g => g.Key);

// Get the duplicate item XML elements using the duplicate keys
var duplicateItems = items.Where(i => duplicateItemKeys.Contains(i.Attribute("creator").Value))
     .OrderBy( xelement => xelement.Attribute("id").Value );

// Get the child nodes named childB
var allItemB = new List<XElement>();
allItemB.AddRange( duplicateItems.Descendants("childB") );

这篇关于Linq XML后代在枚举时丢失的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆