2013-05-28 67 views
7

現在我將開始說這確實是一種分配。但是我已經接近完成了,直到我遇到了Linq to XML語法。LINQ to XML - 如何正確地使用XDocument

我有2個班級:跟蹤和CD現在作爲分配的一部分我創建一個CD,然後添加一些曲目。搜索了很多教程,完美地解釋瞭如何從xml到對象,我似乎無法得到這個工作(對象爲XML)。

我目前有:

//My list of cds 
List<CD> cds = new List<CD>(); 
//Make a new CD and add some tracks to it 
CD c1 = new CD("Awake","Dream Theater"); 
Track t1 = new Track("6:00", "Dream Theater", new TimeSpan(00, 05, 31)); 
Track t2 = new Track("Caught in a Web", "Dream Theater", new TimeSpan(00, 05, 28)); 
Track t3 = new Track("Innocence Faded", "Dream Theater", new TimeSpan(00, 05, 34)); 
c1.addTrack(t1); 
c1.addTrack(t2); 
c1.addTrack(t3); 
cds.Add(c1); 

//Make another cd and add it 
CD c2 = new CD("Second cd","TestArtist"); 
Track t4 = new Track("TrackForSecond","TestArtist",new TimeSpan(00,13,37)); 
c2.addTrack(t4); 
cds.add(c2); 

現在,這是什麼讓我,我需要投入XML的對象。到XML部分是:

XDocument xmlOutput = new XDocument (
    new XDeclaration("1.0","utf-8","yes"), 
    (from cl in cds orderby cl.getArtist() 
     select new XElement("cd", /*From new to the end of this is the error*/ 
      (
       from c in cds 
        select new XAttribute("artist",c.getArtist()) 
      ), 
      (
       from c in cds 
        select new XAttribute("name", c.getTitle()) 
      ), 
      new XElement("tracks", 
       (
        from t in c1.getTracks() 
         select new XElement("track", 
          new XElement("artist",t1.getArtist()),  
          new XElement("title",t1.getTitle()), 
          new XElement("length",t1.getLength()) 
         )   
       )      
      ) 
     ) 
    )     
); 
Console.WriteLine(xmlOutput); 

這很好(讓我得到我需要的結果!)僅1 CD。當我決定添加另一張cd時,它顯示:

An unhandled exception of type 'System.InvalidOperationException' occurred in System.Xml.Linq.dll 
Duplicate Attribute (cd) 

這是指向XDocument。除了這個不工作,感覺非常愚蠢的(從C在CDS×2),但無論我嘗試,我似乎無法從恨我停止這種語法:

(
from c in cds 
    select new XAttribute("artist",c.getArtist()),  
    select new XAttribute("name", c.getTitle()) //No not happening! 
), 

會很樂意與任何幫助,您可以提供!

+0

爲什麼不使用'XmlSerializer'類,然後將結果解析爲'XDocument'? – LukeHennerley

+0

@LukeHennerley我還沒有聽說過,老師正在展示這些結構。 –

+2

這看起來是一個很好的方式來問一個作業問題..你似乎錯過了什麼行異常發生雖然? – Sayse

回答

7

首先,我建議你使用的方法,屬性和C#樣式命名這裏是你的類可以如何進行重構。 :

public class CD 
{ 
    private readonly List<Track> _tracks = new List<Track>(); 

    public CD(string artist, string title) 
    { 
     Artist = artist; 
     Title = title; 
    } 

    public string Artist { get; private set; } 
    public string Title { get; private set; } 

    public IEnumerable<Track> Tracks 
    { 
     get { return _tracks; } 
    } 

    public void AddTrack(Track track) 
    { 
     _tracks.Add(track); 
    } 

    public CD WithTrack(string title, TimeSpan length) 
    { 
     AddTrack(new Track(Artist, title, length)); 
     return this; 
    } 
} 

這是Value Object類 - 私人制定者不允許改變這種課堂外的屬性值這裏是類曲目:

public class Track 
{ 
    public Track(string artist, string title, TimeSpan length) 
    { 
     Artist = artist; 
     Title = title; 
     Length = length; 
    } 

    public string Artist { get; set; } 
    public string Title { get; private set; } 
    public TimeSpan Length { get; private set; } 
} 

現在你可以使用Fluent API來製作CD的集合:

List<CD> cds = new List<CD> 
    { 
     new CD("Awake", "Dream Theater") 
      .WithTrack("6:00", new TimeSpan(00, 05, 31)) 
      .WithTrack("Caught in a Web", new TimeSpan(00, 05, 28)) 
      .WithTrack("Innocence Faded", new TimeSpan(00, 05, 34)), 
     new CD("Second cd", "TestArtist") 
      .WithTrack("TrackForSecond", new TimeSpan(00, 13, 37)) 
    }; 

這裏是XML創建:

var xDoc = new XDocument(
    new XDeclaration("1.0", "utf-8", "yes"), 
    new XElement("cds", 
      from cd in cds 
      orderby cd.Artist 
      select new XElement("cd", 
       new XAttribute("artist", cd.Artist), 
       new XAttribute("name", cd.Title), 
       from t in cd.Tracks 
       select new XElement("track", 
        new XElement("artist", t.Artist), 
        new XElement("title", t.Title), 
        new XElement("length", t.Length))); 

您在這裏度過了幾個問題 - 缺少根節點,並列舉了每次迭代的所有CD。

1
select new XElement("cd", /*From new to the end of this is the error*/ 
     (
      from c in cds 
       select new XAttribute("artist",c.getArtist()) 
     ), 

這將創建命名的元素cd(這是好的),但隨後試圖收集,這是幾乎可以肯定不是你想要的東西在添加一個artist屬性每一個CD,並且是原因的問題。

也就是說,該代碼試圖做這樣的XML:

<cd 
    artist="Dream Theater" 
    artist="TestArtist" 
// the later stuff 

你可能知道是非法的XML。

你缺少的想法是,在這裏:

(from cl in cds orderby cl.getArtist() 

您使用LINQ做循環爲你 - withint這from的範圍,c1是從集合一個特定的CD。所以,你不需要這個內做from c in cds,因爲你已經得到了CD對象,你需要:

select new XElement("cd", /*From new to the end of this is the error*/ 
     select new XAttribute("artist",c1.getArtist()), 
     select new XAttribute("name", c1.getTitle()), 
     new XElement("tracks", 
      (
       from t in c1.getTracks() 
        select new XElement("track", 
         new XElement("artist",t1.getArtist()),  
         new XElement("title",t1.getTitle()), 
         new XElement("length",t1.getLength()) 
        )   
      )      
     ) 
    ) 
) 

你已經在選擇了c1.getTracks()想法是正確的;在創建屬性時應用相同的想法。

3

您的XDocument構造有幾個問題。

  1. XDocument中必須只有一個根元素。您的陳述正在爲每張CD構建一個根元素。
  2. 您的LINQ中有奇怪的嵌套循環。首先由藝術家訂購CD,然後在製作藝術家和名稱屬性時再次遍歷整個CD收藏集。您想從「當前」CD生成這些屬性。
  3. 您在LINQ中使用「c1」和「t1」而不是迭代變量「cl」和「t」。

試試這個(原諒我將你的getter/setter方法爲屬性:

var xmlOutput = new XDocument(
    new XDeclaration("1.0", "utf-8", "yes"), 
    new XElement(
     "cds", 
     from cd in cds 
     orderby cd.Artist.ToUpperInvariant() 
     select new XElement(
      "cd", 
      new XAttribute("title", cd.Title), 
      new XAttribute("artist", cd.Artist), 
      new XElement(
       "tracks", 
       from t in cd.Tracks 
       select new XElement(
        "track", 
        new XAttribute("artist", t.Artist), 
        new XAttribute("title", t.Title), 
        new XAttribute("length", t.Length))))));