tags:

views:

423

answers:

3

Hi All

Is there a way to Take a given XML file and convert (preferably using C# Generics) it into a Concrete Ienumerable list of T where T is my concrete class

So for example I may have an XML file like

<fruits>
    <fruit>
     <id>1</id>
     <name>apple</name>
    </fruit>
    <fruit>
     <id>2</id>
     <name>orange</name>
    </fruit>
</fruits>

and I would like to see a list of a Fruit Objects

where it has properties like

public class Fruit : IFruit
{
    public string name;
    public int id;
}

I assume I'd need some kind of Mapping if I was to use generics, as I would like this to work for ideally the IFruit interface (not sure if thats possible)

Thanks in advance

A: 

I'm not sure I fully understand your circumstances, but one approach is to define a data transfer class and make it serializable in XML. Then you can deserialze the XML into an array of objects.

edit

I'm not going to delete this, but I think that what Andrew Hare posted is closer to what you want, and I've up-voted him in support.

Steven Sudit
@Steven - Sorry, I deleted my post, rethought the problem, then undeleted my answer after an edit. Sorry for the confusion!
Andrew Hare
No problem. I'll remove the duplicate code to avoid confusion.
Steven Sudit
+4  A: 

Given the following types:

public interface IFruit
{
    String name { get; set; }
    Int32 id { get; set; }
}

public class Fruit : IFruit
{
    public String name { get; set; }
    public Int32 id { get; set; }
}

I think that you could do something like this:

    static IEnumerable<T> GetSomeFruit<T>(String xml)
     where T : IFruit, new()
    {
     return XElement.Parse(xml)
      .Elements("fruit")
      .Select(f => new T {
       name = f.Element("name").Value,
       id = Int32.Parse(f.Element("id").Value)
      });
    }

Which you would call like this:

IEnumerable<Fruit> fruit = GetSomeFruit<Fruit>(yourXml);
Andrew Hare
I like this solution, and it's actually compatible with also enabling XML serialization. The only comment I'd make is that .NET conventions typically require that public fields (or, more realistically, public properties) start with a capital letter, but that was Harrison's decision, not yours.
Steven Sudit
Nice.To take this a step further I would imagine there would be subclasses for each type of fruit for a generic method such as this to return fruit nodes of a matching type i.e if T=Orange then only return those fruits whose name is Orange. The method could compare the typeof(T).Name to the name of the fruit from the xml and exclude others... just my 2 cents
Abhijeet Patel
+3  A: 

Here's a way to do it with serialization, if that's your thing:

using System;
using System.IO;
using System.Xml.Serialization;

public static class Test
{
 public static void Main(string[] args)
 {
  var fs = new FileStream("fruits.xml", FileMode.Open);
  var x = new XmlSerializer(typeof(Fruits));
  var fruits = (Fruits) x.Deserialize(fs);
  Console.WriteLine("{0} count: {1}", fruits.GetType().Name, fruits.fruits.Length);
  foreach(var fruit in fruits.fruits)
   Console.WriteLine("id: {0}, name: {1}", fruit.id, fruit.name);
 }
}

[XmlRoot("fruits")]
public class Fruits
{
    [XmlElement(ElementName="fruit")]
    public Fruit[] fruits;
}

public class Fruit
{
    public string name;
    public int id;
}
brianary
Thanks for putting together sample code to flesh out my off-the-cuff suggestion.
Steven Sudit
Thanks this has made it much clearer in my head. I had difficulty figuring the generics part out as I have not done much serialization with XML - perfect!
harrisonmeister