views:

266

answers:

1

I have an XML configuration file that contains a list of documents with field maps for each document. I want to use LINQ to XML to populate an internal data structure which represents the documents as a hierarchy of List<> structures.

An attribute called Include determines whether the field should be included.

Here is a sample of what the XML looks like:

<Documents>
  <Document Include="1" DocumentName="Report1" >
    <Field Include="1" OldName="Old1" NewName="New1"/>
    <Field Include="1" OldName="Old2" NewName="New2"/>
    <Field Include="0" OldName="Old3" NewName="New3"/>
  </Document>
  <Document Include="1" DocumentName="Report2" >
    <Field Include="1" OldName="Old1" NewName="New1"/>
    <Field Include="0" OldName="Old3" NewName="New3"/>
  </Document>
</Documents>

The datastructure representing the documents looks like this:

class FieldMap
{
    public string OldName { get; set; }
    public string NewName { get; set; }
}

class Document
{
    public string DocumentName { get; set; }
    public List<FieldMap> FieldMaps;
}

private List<Document> Documents;

Below is code I have that does the first part by populating the Documents:

var ds = from row in elem.Descendants("Document")
         where row.Attribute("Include").Value == "1"
         select new Document
         {
            DocumentName = row.Attribute("DocumentName").Value,
         };

Documents = ds.ToList<Document>();

I would like to modify the code above so that it also populates the List structure within each Document. I know I could do this by iterating through the Documents List<> and running another LINQ query in the loop however I would prefer to do everything as a consolidated query.

+2  A: 

Have you tried something like this: ?

var ds = from row in elem.Descendants("Document")
         where row.Attribute("Include").Value == "1"
         select new Document
         {
            DocumentName = row.Attribute("DocumentName").Value,
            FieldMaps =    //Solution from here
               (from field in row.Descendants ("Field")
                where field.Attribute("Include").Value == "1"
                select new FieldMap {
                    OldName = field.Attribute("OldName").Value,
                    NewName = field.Attribute("NewName").Value
                }).ToList () //To here
         };

Documents = ds.ToList<Document>();

Some people says that it's clearer to popullate the FielMaps properties outside the LINQ query using a foreach, i don't agree with that, but if you like that alternative it would look like something like:

var ds = from row in elem.Descendants("Document")
         where row.Attribute("Include").Value == "1"
         select new Document
         {
             DocumentName = row.Attribute("DocumentName").Value
         };

Documents = ds.ToList<Document>();

foreach (var document in Documents)
    document.FieldMaps = elem.Descendants("Document")
        .Where(doc => doc.Attributes("DocumentName") == document.DocumentName)
        .Select(doc => doc.Descendants("Fields"))
        .Where(field => field.Attributes("Include").Value == "1")
        .Select(field => new FieldMap
            {
                OldName = field.Attributes("OldName").Value,
                newName = field.Attributes("NewName").Value
            }
        ).ToList();
AlbertEin
The first approach worked great.
Matt Spradley