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

これは機能しますが、後でduplicateItemsを使用しようとすると問題が発生します。(foreachduplicateItemsのように)列挙するときはいつでも、最初のアイテムはその子のコンテキストを失います。2つ目は問題ありません。

たとえば、コードの後半で私は言います

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

「allItemB」には、最初のパスで2が含まれ、2番目のパスで234が含まれると予想されます。結局のところ、duplicateItems配列が列挙されると、最初のXElementがその子を失うため、34個しか含まれていません。

誰かがこれを修正する方法を知っていますか?

4

1 に答える 1

2

私があなたの質問を正しく理解しているなら、allItemBに3つの要素を持たせたいと思います-allItemB [0]は値2、[1]が3、[2]が4のXElement childBですか?

もしそうなら、問題はあなたがduplicateItemsを宣言しているところです。変数のスコープは最初のforeachループに制限されているため、同じコードはコンパイルされません。したがって、2番目のループでは使用できません。

上記の結果を得るための私のコード:

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

編集:サンプルのxmlファイルにCreatedOn属性がなかったため、最初のforeachループでOrderByを変更したことを忘れました。

また、必要に応じて、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 に答える