views:

182

answers:

2

I'm working on a Silverlight web application that works with XML similar to:

<?xml version="1.0" encoding="UTF-8" ?> 
<ProjectList>
    <Type>web</Type> 
    <Project>
     <Id>1</Id> 
     <Name>test web project</Name> 
     <Description>test web project</Description> 
     <ScreenshotList>
      <Screenshot>
       <Path>screen1.jpg</Path> 
       <Description>This a description of screen 1</Description> 
      </Screenshot>
      <Screenshot>
       <Path>screen2.jpg</Path> 
       <Description>This a description of screen 2</Description> 
      </Screenshot>
      <Thumb>noThumb.jpg</Thumb> 
     </ScreenshotList>
    </Project>
</ProjectList>

I would like to create a new object for each Project element in the XML. I have a class called project which contains fields for id, name, description, thumb and a list for all the screenshots.

My current LINQ code looks like:

var projects = from project in xDoc.Root.Elements("Project")
                       select new Project(
                                    Int32.Parse(project.Element("Id").Value, CultureInfo.InvariantCulture),
                                    project.Element("Name").Value,
                                    project.Element("Description").Value,
                                    project.Element("ScreenshotList").Element("Thumb").Value
                                    );

Is there anyway for me to easily get the screenshots and add them to the list in the instance of Project within this one query?

EDIT - Adding Project constructor
public Project(int id, string name, string description, string thumbPath)
{
     this.id = id;
     this.name = name;
     this.description = description;
     this.thumbPath = thumbPath;
}
+2  A: 

Well, you haven't shown what the Project constructor looks like... does it let you pass in the screenshots as an IEnumerable<Screenshot>? If so, it should be easy... something like:

var projects = 
    from p in xDoc.Root.Elements("Project")
    select new Project(Int32.Parse(project.Element("Id").Value, 
                                   CultureInfo.InvariantCulture),
                       p.Element("Name").Value,
                       p.Element("Description").Value,
                       p.Element("ScreenshotList")
                        .Element("Thumb").Value,
                       p.Element("ScreenshotList")
                        .Elements("Screenshot")
                        .Select(ss => 
                            new Screenshot(ss.Element("Path").Value,
                                           ss.Element("Description").Value))
                      );

(I've reformatted a bit to avoid scrolling.)

Jon Skeet
I added my current constructor. I will try passing them in as a parameter to it now.
Jason
That worked :) Thanks!
Jason
+3  A: 

Something like:

    var projects = from project in xDoc.Root.Elements("Project")
                   let list = project.Element("ScreenshotList")
                   select new Project(
                        (int) project.Element("Id"),
                        (string)project.Element("Name"),
                        (string)project.Element("Description"),
                        (string)list.Element("Thumb"),
                        from scr in list.Elements("Screenshot")
                        select new Screenshot(
                            (string)scr.Element("Path"),
                            (string)scr.Element("Description")
                        )
                   );

Based on types like:

class Project {
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public string Thumb { get; set; }
    public List<Screenshot> Screenshots { get; private set; }
    public Project( int id, string name, string description, string thumb,
            IEnumerable<Screenshot> screenshots) {
        this.Id = id;
        this.Name = name;
        this.Description = description;
        this.Thumb = thumb;
        this.Screenshots = screenshots == null ? new List<Screenshot>()
                 : new List<Screenshot>(screenshots);
    }
}
class Screenshot {
    public string Path { get; set; }
    public string Description { get; set; }
    public Screenshot(string path,string description) {
        this.Path = path;
        this.Description = description;
    }
}
Marc Gravell
Your solution worked to but I gave Jon Skeet the mark cos he got there first. Thanks
Jason
Actually from looking at it again, I like this query more. You get the tick!
Jason