7

Now I will start off by saying this is indeed an assigment. I have however nearly finished it untill I ran into the Linq to XML syntax.

I have 2 classes: Track and CD now as part of the assigment I create a cd and then added some tracks to it. After searching for lots of tutorials that explained perfectly how to go from xml to objects I just cannot seem to get this working (objects to xml).

I currently have:

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

Now this is what gets me the objects I need to put into XML. The to XML part is:

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

This works great (gets me the result I need!) for just 1 cd. When I decide to add another cd it shows:

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

Which is pointing at the XDocument. Aside from this not working it feels pretty stupid (from c in cds x2) but whatever I try I cannot seem to stop this syntax from hating me:

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

Would be very happy with any help you can provide!

4

3 回答 3

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

这是值对象类 - 私有设置器不允许更改此类之外的属性值。这是轨道类:

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。

于 2013-05-28T15:50:02.323 回答
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))))));
于 2013-05-28T15:37:15.990 回答
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(这很好)的元素,然后尝试为集合中的每张 CDartist添加一个属性,这几乎肯定不是您想要的,并且是问题的原因。

也就是说,这段代码试图使 xml 像这样:

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

您可能知道这是非法的 xml。

您缺少的想法是:

 (from cl in cds orderby cl.getArtist()

您正在使用 LINQ 为您执行循环 - 在此范围内fromc1该集合中的一张特定 CD。所以你不需要from c in cds 在 this中做,因为你已经得到了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())
                   )          
           )                    
        )
    )
)  

您已经有了选择 over 的正确想法c1.getTracks();在创建属性时应用相同的想法。

于 2013-05-28T15:35:28.283 回答