0

我有一个这样的 XML 文档

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

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

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

这可行,但是稍后当我尝试使用重复项时出现问题。任何时候它枚举(如在 foreach duplicateItems 中)第一个项目都会失去其子项的上下文。第二个刚刚好。

因此,例如,稍后在代码中我说

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

我希望“allItemB”在第一遍包含 2,然后在第二遍包含 234。最终发生的是它只包含 34,因为一旦枚举了 duplicateItems 数组,第一个 XElement 就会失去它的孩子。

有谁知道如何解决这一问题?

4

1 回答 1

2

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

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

我的代码得到上述结果:

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 属性。

如果你愿意,你可以使用更多的 Linq 并完全放弃 foreach 循环,如下所示:

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") );
于 2012-07-07T03:20:40.133 回答