SoftwareSavant
SoftwareSavant

Reputation: 9737

Turning XML string into List of Objects using Linq

I am attempting to turn an XML string into an a regular collection of .net Objects using Linq (I hate linq... Mainly because I have little time to learn precisely how it works, and consequently, I am always confused as hell when things go wrong). I wish there was a nice and easy way using like an XSD or something, and some kind of deserializer, and reserializer... But there doesn't seem to be any native support in .net. So I figured, why not just use Linq? Big mistake. But anyway, I want to to turn this string...

<?xml version="1.0" encoding="utf-16"?>
  <ArrayOfPopulation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Population>
  <id>3</id>
  <name>CHF</name>
  <description>FR Congestive Heart Failure</description>
  <createdDate>2011-10-25T04:00:00Z</createdDate>
  <createdUserID>WPS_ANEMIA_POP_OWNER</createdUserID>
  <modifiedDate>2011-10-31T04:00:00Z</modifiedDate>
  <modifiedUserID>WPS_ANEMIA_POP_OWNER</modifiedUserID>
  <isActive>true</isActive>
  <owner>
    <type>AD GROUP</type>
  </owner>   
  <owner>
    <type>ACCOUNT</type>
  </owner>
  <type>
    <name>ACO SURVEY</name>
  </type>
  </Population>
  <Population>
  <id>2</id>
  <name>COPD</name>
  <description>FR Chronic Obstructive Pulmonary Disease</description>
  <createdDate>2011-10-25T04:00:00Z</createdDate>
  <createdUserID>WPS_ANEMIA_POP_OWNER</createdUserID>
  <modifiedDate>2011-10-31T04:00:00Z</modifiedDate>
  <modifiedUserID>WPS_ANEMIA_POP_OWNER</modifiedUserID>
  <isActive>true</isActive>
  <owner>
    <domain>1UPMC-ACCT</domain>
    <name>InteropDev</name>
    <type>AD GROUP</type>
  </owner>
  <owner>
    <domain>1UPMC-ACCT</domain>
    <name>ACOPopulationUsers</name>
    <type>AD GROUP</type>
  </owner>
  <owner>
    <domain>1UPMC-ACCT</domain>
    <name>muesml</name>
    <type>ACCOUNT</type>
  </owner>
  <owner>
    <domain>1UPMC-ACCT</domain>
    <name>andersonjm</name>
    <type>ACCOUNT</type>
  </owner>
  <type>
    <name>ACO SURVEY</name>
  </type>
 </Population>
 </ArrayOfPopulation>

Into an array of these objects...

public class PopulationModel
{
    public string populationID { set; get; }

    public string PopName { set; get; }

    public string Description { set; get; }

    public int PopulationType { set; get; }

    public int isActive { set; get; }

    //public List<XSLTACOData> patients { set; get; }
}

Which would kind of look like this...

public class PopulationsModel
{
    public List<PopulationModel> Populations { set; get; }
}

I am failing to do this using this linq to XML query...

XDocument xDocument = XDocument.Parse(xmlFromSvc);
XElement elem = xDocument.Element("ArrayOfPopulation");
//client.GetOwnedPopulations();
IEnumerable<PopulationsModel> popModel = (IEnumerable<PopulationsModel>)
     (from templates in elem.Elements("Population")
      select new PopulationModel
      {
          populationID = templates.Attribute("id").Value,
          PopName = templates.Attribute("name").Value,
          Description = templates.Attribute("description").Value,
          PopulationType = int.Parse(templates.Attribute("").Value),
          isActive = int.Parse(templates.Attribute("isActive").Value)
      }).ToList();

I am officially confused. Why on earth doesn't this work? Also, there has to be an easier way to get this done? This seems like the perfect thing for xsd's and all that other crap. I am working to hard here perhaps?

Now getting this exception...

Unable to cast object of type  'System.Collections.Generic.List`1[FocusedReadMissionsRedux.Models.PopulationModel]' to type 'System.Collections.Generic.IEnumerable`1[FocusedReadMissionsRedux.Models.PopulationsModel]'.

This seems like a slightly more reasonable exception.

Upvotes: 1

Views: 561

Answers (2)

MarcinJuraszek
MarcinJuraszek

Reputation: 125610

You are trying to get value using Attribute method, when they are actualy elements.

Try this one (I haven't tested it to be honest):

XDocument xDocument = XDocument.Parse(xmlFromSvc);
XElement elem = xDocument.Element("ArrayOfPopulation");

var popModel = (from templates in elem.Elements("Population")
                select new PopulationModel
                {
                     populationID = (string)templates.Element("id"),
                     PopName = (string)templates.Element("name"),
                     Description = (string)templates.Element("description"),
                     PopulationType = (int)templates.Element("Type").Element("Name"),
                     isActive = (int)templates.Element("isActive")
                }).ToList();

Upvotes: 2

Jon Skeet
Jon Skeet

Reputation: 1499800

Why on earth doesn't this work?

Well, let's look at what you're doing. You've got templates as a <Population> element, and then you're querying it like this:

  populationID = templates.Attribute("id").Value,
  PopName = templates.Attribute("name").Value,
  Description = templates.Attribute("description").Value,
  PopulationType = int.Parse(templates.Attribute("").Value),
  isActive = int.Parse(templates.Attribute("isActive").Value)

Note how you're using Attribute here for everything. Now look at the XML:

<Population>
  <id>3</id>
  <name>CHF</name>
  ...
</Population>

The Population element doesn't have any attributes. It has nested elements. I haven't checked in detail, but changing all of your Attribute calls to Element calls may well fix everything except PopulationType. (It's not clear where you're trying to get that from.)

Note that the explicit conversions from XAttribute and XElement are generally cleaner to use than int.Parse etc.

Upvotes: 4

Related Questions