2016-10-04 11 views
3

xmlドキュメントからXElementを選択し、xmlドキュメントの2つの "レベル"で一致させようとしています。私が別のライブラリのノードにこの要素とすべての子要素をコピーすることができるようにlinqを使用して2つの要素レベルに一致するxml要素を見つける

​​

そして、私は図書館で読書リスト名「TEST2」を見つけたい「メイン」:私のファイル構造です。

私はこれを学ぼうとしているので、私はlinqを使用したソリューションを好むでしょう。任意のヘルプ

を事前に

おかげで、私は新しい「リーディングリスト」を追加し、私はそれをこのように実行します。

public void AddReadingList(string fullyQualifiedPath, Library lib, string name) 
{ 
    XDocument xdoc = XDocument.Load(fullyQualifiedPath); 

    XElement library = xdoc.Element("eStack").Elements("Library") 
       .Single(x => x.Attribute("Name").Value == lib.Name); 

    library.Add(new XElement("ReadingList", new XAttribute("Name", name))); 

    xdoc.Save(fullyQualifiedPath);       
} 

を私は実行する操作は、この要素のコピーであり、サブ要素。問題は、同じ名前を持つ複数の "library"要素がある可能性があるため、ライブラリ名と読み取りリスト名を確認する必要があるということです。それは理にかなっていますか?

var result = XDocument.Load(fullyQualifiedPath) 
    .Descendants("Library") 
     //Can replace with `FirstOrDefault` if you know there is only one 
    .Where(element => element.Attribute("Name")?.Value == "Main") 
    .Descendants("ReadingList") 
    .Where(element => element.Attribute("Name")?.Value == "Test2").ToList(); 

あなたはまた、私はまたappやその他のレベルを指定しないようにして、それを使用することが好ましい代わりDescendants.Elementsを使用することができますトリックを行います.DescendantsWhere秒の組み合わせを使用して

+1

あなたが私たち何」で共有することはできますが、やった? –

答えて

2

途中で

あなたが行うことができます前に、C#6.0の場合

var result = XDocument.Load("data.xml") 
    .Descendants("Library") 
    .Where(element => 
    { 
     var att = element.Attribute("Name"); 
     return att != null ? (att.Value == "Main" ? true : false) : false; 
    }) 
    .Descendants("ReadingList") 
     //Make sure to do above change here too 
    .Where(element => element.Attribute("Name")?.Value == "Test2").ToList(); 

またはその代わりに、コードを繰り返すことで、それを支援するための方法を作成する場合:

Func<XElement, string, string> tryGetAttributeValue = (element, attributeName) => 
{ 
    var attribute = element.Attribute(attributeName); 
    return attribute == null ? string.Empty : attribute.Value; 
}; 

var result = XDocument.Load("data.xml") 
    .Descendants("Library") 
    .Where(element => tryGetAttributeValue(element,"Name") == "Main") 
    .Descendants("ReadingList") 
    .Where(element => tryGetAttributeValue(element, "Name") == "Test2").ToList(); 
+0

whereステートメントの.Valueが機能していないようです。これが正しいと確信していますか? – cbutler

+0

無効な表現用語 'を取得しています。両方の.Valueに。どこの部分。これがなぜなのか? – cbutler

+1

@cbutler - はい。どのようなC#を使用していますか?私はあなたがC#6.0以前であると仮定しているので、 '? 'は動作しません。 –

0

あなたのような何かを探していますこの?

 var table = XElement.Parse(@"<app> 
             <Library Name=""Main"" Path=""C:\somefile.Xml""> 
              <ReadingList Name=""Test1""> 
               <Book>Book1</Book> 
              </ReadingList> 
              <ReadingList Name=""Test2""> 
               <Book>Book2</Book> 
              </ReadingList> 
             </Library> 
             <Library Name=""Backup"" Path=""C:\somefile.Xml""></Library> 
            </app>"); 


     var readingList = table 
      .Elements("Library") 
      .FirstOrDefault(x => x.Attribute("Name")?.Value == "Main") 
      .Elements("ReadingList") 
      .FirstOrDefault(x => x.Attribute("Name")?.Value == "Test2"); 

これは、本質的にTest2という名前とTest 1という名前ReadingList下さReadingListを得ることのあなたのクエリを解決するだろう。

FirstOrDefaultの代わりにWhereを選ぶことができますが、それは可能性のあるすべての一致のリストで終わるでしょう。

 var readingList = table 
      .Elements("Library") 
      .Where(x => x.Attribute("Name").Value == "Main") 
      .Elements("ReadingList") 
      .Where(x => x.Attribute("Name").Value == "Test2") 
      .ToList(); 

子孫バリアントを選択すると、結果的にはあまり表示されません。

ます。また、このクエリを行うことができます
 var readingList = table 
      .Descendants("Library") 
      .Where(x => x.Attribute("Name").Value == "Main") 
      .Descendants("ReadingList") 
      .Where(x => x.Attribute("Name").Value == "Test2") 
      .ToList(); 
+1

2番目の 'Descendants' /' Elements'の前の '? '演算子は必要ありません。それは決してnullにはなりません。もし見つからなければ、それは 'Enumerable.Empty'になるでしょう –

+0

真実は気付かなかった。一定 –

0

var query= xdoc.Descendants("Library") 
       .Where(e=>e.Attribute("Name").Value=="Main") 
       .SelectMany(e=>e.Elements("ReadingList").Where(t=>t.Attribute("Name").Value=="Test2")); 

あなたもFirstOrDefault拡張メソッドを使用することができますちょうど1 Mainの要素がある場合:

var query= xdoc.Descendants("Library") 
       .FirstOrDefault(e=>e.Attribute("Name").Value=="Main") 
       .Descendants("ReadingList").Where(t=>t.Attribute("Name").Value=="Test2")); 
関連する問題