LINQ to XML - 如何正确使用XDocument

Flo*_*man 7 c# xml linq linq-to-xml

现在我首先要说这确实是一种贬义.然而,我几乎完成了它,直到我遇到了Linq to XML语法.

我有两个类:Track和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);
Run Code Online (Sandbox Code Playgroud)

现在,这就是我需要将其放入XML的对象.to 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);
Run Code Online (Sandbox Code Playgroud)

这很好用(得到我需要的结果!)仅1 cd.当我决定添加另一张CD时,它会显示:

An unhandled exception of type 'System.InvalidOperationException' occurred in System.Xml.Linq.dll
Duplicate Attribute (cd)
Run Code Online (Sandbox Code Playgroud)

这是指向XDocument.除了这不工作之外它感觉非常愚蠢(来自cds x2中的c)但是无论我尝试什么,我似乎无法阻止这种语法恨我:

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

如果您能提供任何帮助,我们将非常满意!

Ser*_*kiy 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是Value Object类 - 私有setter不允许更改此类之外的属性值.这里是轨道课程:

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; }
}
Run Code Online (Sandbox Code Playgroud)

现在,您可以使用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))
    };
Run Code Online (Sandbox Code Playgroud)

这是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)));
Run Code Online (Sandbox Code Playgroud)

这里有几个问题 - 缺少根节点,并在每次迭代时枚举所有CD.