2016-09-08 8 views
2

取得したいxml子ノードを持つHas​​hSetがあります。LINQを使用した値のHashSetから親の子孫を確認する

のxml:

<team> 
    <bob>a</bob> 
    <mary>b</mary> 
    <joe>c</joe> 
</team> 
<team> 
    <john>d</john> 
</team> 

HashSetの:

HashSet<string> people = new HashSet<string> { "mary", "joe", "john" }; 

LINQ:

IEnumerable<XElement> result = from d in doc.Descendants("team") 
           where people.Contains(d.Descendants().Name.LocalName) 
           select d; 
私はすべてのチャイルズを取得しようとも親を返すために、次のLINQ(動作しない)を使用しています

返信:

<team> 
    <mary>b</mary> 
    <joe>c</joe> 
</team> 
<team> 
    <john>d</john> 
</team> 

しかし動作しません。どんな助けもありがとう。ありがとう。

何も返さない、私は完全な例を追加してい1

更新#、:

public void test1() 
     { 
      var xml = 
        @"<?xml version=""1.0"" encoding=""utf-8""?> 
         <hereistheroot> 
          <team> 
           <bob>a</bob> 
           <mary>b</mary> 
           <joe>c</joe> 
          </team> 
          <team> 
           <john>d</john> 
          </team> 
         </hereistheroot>"; 
      XElement doc = XElement.Parse(xml); 

      HashSet<string> people = new HashSet<string> { "mary", "joe", "john" }; 

      IEnumerable<XElement> result = from d in doc.Descendants("team") 
              where people.Contains(d.Name.LocalName) 
              select d; 

     } 

それは何も返しません。 、テストのためにLINQで "どこ" 条項を削除し、それは以下となります。

まず1:

<team> 
    <mary>b</mary> 
    <joe>c</joe> 
</team> 

二つ目:

<team> 
    <john>d</john> 
</team> 

これは、2つのXElementオブジェクトを返す必要があります2つのXElementオブジェクトを正しく返しますが、これが主な問題です.HashSetに基づいて人を選択できるようにするには、「Where」節を取得する必要があります。ありがとう。

+0

代わりに結果は何ですか?また、上記のXMLは有効なXMLではありません。なぜなら、名前ノード上の終了タグが与えられていないからです。 ( ''の代わりに '')。また、XMLに複数のルート要素があるように見えますが、これは許可されていません。 –

+0

マックス、ありがとう、それが修正されました。結果はありません.d.Descendants()。Name.LocalNameにエラーがあります。 –

+0

doc.ElementsにおけるDからのLINQクエリ '( "チーム")子孫()people.Contains(d.Name.LocalName)は、Dを選択し、' 'ノード B C D'を返し、メンバーが変更された2つの ''ノードの結果セットが必要なのでしょうか?それとも、あなたが望むもの、3ノードの結果セットですか?必要に応じて、いつでもコード内のこれら3つのノードの親にアクセスすることができます。 –

答えて

1

あなたが実際にここに二つの異なるものを達成しようとしているように私には思える:

  1. はあなたのセットで名前を持つ子ノードを含むすべてのトップレベルteam要素を識別します。
  2. トップレベルのteam要素のみを含む新しいXML DOMを作成します。これらの要素には、セット内の名前を持つ子ノードのみが含まれます。それが正しいなら

、次はそれを達成します:

IEnumerable<XElement> result = from d in doc.Descendants("team") 
           let validDescendants = d.Descendants() 
            .Where(c => people.Contains(c.Name.LocalName)).ToArray() 
           where validDescendants.Length > 0 
           select new XElement(d.Name, validDescendants); 

上記の代替同等、クエリ式の構文の多くを使用して(つまりはvalidDescendantsを初期化する):

IEnumerable<XElement> result = from d in doc.Descendants("team") 
           let validDescendants = 
            (from c in d.Descendants() 
            where people.Contains(c.Name.LocalName) 
            select c).ToArray() 
           where validDescendants.Length > 0 
           select new XElement(d.Name, validDescendants); 

この方法では元のdocツリーは変更されず、代わりに完全に新しいteam要素の列挙が返されますあなたの望みに。

あなたではなく、単にそのdocツリーを維持し、返さteam要素から子要素を削除したい場合は、このような何か行うことができます:もちろん

IEnumerable<XElement> result = from d in doc.Descendants("team") 
           where d.Descendants() 
            .Any(c => people.Contains(c.Name.LocalName)) 
           select d; 

foreach (XElement element in result) 
{ 
    foreach (XElement child in element.Descendants().ToList()) 
    { 
     if (!people.Contains(child.Name.LocalName)) 
     { 
      child.Remove(); 
     } 
    } 
} 

を、その一例では、それはそのまま残しますteamの要素は、ではありませんでした。には、名前が設定された要素が少なくとも1つ含まれています。もちろんこれは修正可能ですが、フィルタリング後に空でない要素を検索するだけであるように見えるので、上記の最初の例は、あなたが望む行に沿ったものであると仮定しています。私はあなたがあなたの質問に完全に記述していないことを念頭に置いてより具体的なものを持っているならば、あなたが上に構築するためのバリエーションとしてのみ2番目を示しました。

+0

ピーター、ありがとう、それは素晴らしいです!私自身の知識のための素早い質問(そして私は頭が壊れているので)。上記の最初の例をクエリ式の構文に変換するにはどうすればよいですか?ありがとう。 –

+0

ピーター、まさに私が探していたものでした。とても有難い。 –

+0

さて、うれしいですね。 :) –

関連する問題