2013-05-28 21 views
7

Şimdi bunun gerçekten bir ödev olduğunu söyleyerek başlayacağım. Ancak Linq'den XML sözdizimine geçene kadar neredeyse bitirdim.XML için LINQ - XDocument'i doğru şekilde nasıl kullanırsınız?

2 sınıfım var: Parça ve CD şimdi bir cd olarak oluşturdum ve bir parça oluşturdum. Xml'den nesnelere nasıl gidileceğini mükemmel bir şekilde açıklayan çok sayıda öğretici aradıktan sonra, bu çalışmayı (xml nesnelerini) elde edemiyorum.

Şu anda var:

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

Şimdi bu bana XML içine koymak gerekir nesneleri alır budur. XML bölümüne:

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

Sadece 1 cd için bu harika çalışıyor (ihtiyacım olan sonucu alır!). Başka bir cd eklemeye karar verdiğimde, o, XDocument öğesinde işaret etmektedir. Kenara gelen bu o (CD'ler x2 c itibaren) güzel aptal hissediyor ama benden nefret bu sözdizimi durdurmak için görünmüyor olabilir denemek olursa olsun çalışmıyor:

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

Sağlayabilir herhangi yardımıyla çok mutlu olurdu!

+0

Neden sadece 'XmlSerializer' sınıfını kullanmayın ve daha sonra bir' XDocument' sonucu ayrıştırmak? Bu konuda duymadım – LukeHennerley

+0

@LukeHennerley, öğretmen yapılarının bu tür görüntüleniyor oldu. –

+2

Bu ödev soru sormak için iyi bir yol gibi gözüküyor .. Eğer istisna olsa üzerinde oluştuğunu çizgi ne kaçırmış görünüyor? – Sayse

cevap

7

şeyden önce, sana yöntemlere ilişkin özellikleri ve C# stil adlandırmayı kullanmak önermek İşte sınıflar refactored nasıl olduğunu.

: -: özel belirleyiciler bu sınıfın dışında özellik değerlerini değiştirmek için izin vermez Ve burada parça için sınıftır

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

Bu Value Object sınıftır.

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

Artık CD koleksiyonu oluşturmak için Fluent API kullanabilirsiniz: Burada

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

Ve XML yaratılmasıdır:

Burada bazı sorunlar vardı
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))); 

- kök düğümü eksik ve üzerinde numaralandırma Her iterasyondaki tüm CD'ler.

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()) 
     ), 

Bu adlandırılmış bir öğe yaratacak (iyidir), ama sonra ne istediğinizi neredeyse kesin değil koleksiyonunda, her CD için bir artist niteliğini eklemeye çalışırsanız ve nedenidir cd problemin. Muhtemelen bildiğiniz

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

yasadışı xml geçerli: olup

, bu kodu şöyle xml yapmaya çalışır. Bu from kapsamında withint, c1 koleksiyonundan den belirli bir CD - sizin için döngü yapmak için LINQ kullanan

(from cl in cds orderby cl.getArtist() 

:

eksik fikri burada olmasıdır. Zaten CD nesne var çünkü Yani, bu içinde from c in cdsyapmak gerekmez İhtiyacınız:

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()) 
        )   
      )      
     ) 
    ) 
) 
Zaten c1.getTracks() üzerinde seçiminde doğru fikri var

; öznitelikleri oluştururken aynı fikri uygular.

3

XDocument yapınızda birkaç sorun var.

  1. Bir XDocument öğesinde tam olarak bir kök öğesi olmalıdır. İfadeleriniz her CD için bir kök eleman inşa ediyor.
  2. LINQ'nuzda garip iç içe döngüler var. Öncelikle CD'leri sanatçıya göre sıralıyorsunuz ve daha sonra, sanatçı ve ad özniteliklerini üretirken tüm CD koleksiyonunda tekrar yineliyorsunuz. Bu öznitelikleri "geçerli" CD'den üretmek istiyorsunuz.
  3. Sen "c1" ve "t1" senin LINQ yerine yineleme değişkenleri "cl" ve "t" kullanıyoruz.

bu (özelliklerine içine getters/ayarlayıcıları dönüm için beni affet deneyin:

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)))))); 
İlgili konular