0

I need to import a XML file looking like this:

<Carpark>
   <Trucks>
      <Truck brand='Chrysler' kg='2100'/>
   </Trucks>
   <Cars>
      <Car brand='Mercedes' kg='1100'/>
   </Cars>
   <Tractors>
      <Tractor brand='John Deere' kg='1500'/>
   </Tractors>
</Carpark>

Essentially I want to have a list of Carpark like this:

public class Carpark
{
    // Type can be for example Truck, Car
    public string Type { get; set; }
    public string Brand { get; set; }
    public int Weight { get; set; }
}

I don't understand how to convert this XML file to the class I want.

What I have tried is:

XElement xElement = XElement.Load(filePath);
IEnumerable<Carpark> carpark = xElement.Elements();

foreach(var vehicle in carpark)
{
    // Once I wrote out the line I was confused as to how to proceed
    Console.WriteLine(vehicle.ToString());
}
      
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Cenderze
  • 1,202
  • 5
  • 33
  • 56
  • If you are using Visual Studio you can use the 'Paste Special' option to past the XML and have it converted to a c# class for you. See this answer on how to do that, [Paste Special](https://stackoverflow.com/questions/4203540/generate-c-sharp-class-from-xml) – quaabaam Jun 21 '23 at 16:51
  • 3
    Also, your Truck, Car, and Tractor elements are not valid XML as they are not properly closed and they need to be in order to be valid XML. If they are not closed then this cannot be considered XML. – quaabaam Jun 21 '23 at 16:52
  • @quaabaam Thank you! Never heard of that feature, I'll definetely check that out! That is true, I forgot to close the elements. Thanks for notifying! – Cenderze Jun 21 '23 at 17:32

2 Answers2

1

You can do that with Linq_To_XML and I believe with NewtonsoftJSON:

void Main()
{
    var xml = XElement.Parse(x)
        .DescendantsAndSelf("Carpark")
        .Descendants()
        .Where(xe => xe.HasAttributes)
        .Select(xe => new Carpark {
            Type = xe.Name.ToString(),
            Brand = (string)xe.Attribute("brand"),
            Weight = (int)xe.Attribute("kg")
        })
        ;
        
    foreach (var cp in xml)
    {
        Console.WriteLine($"{cp.Type}, {cp.Brand}, {cp.Weight}");
    }
    
}

static readonly string x = @"<Carpark>
   <Trucks>
      <Truck brand='Chrysler' kg='2100'/>
   </Trucks>
   <Cars>
      <Car brand='Mercedes' kg='1100'/>
   </Cars>
   <Tractors>
      <Tractor brand='John Deere' kg='1500'/>
   </Tractors>
</Carpark>";

public class Carpark
{
    // Type can be for example Truck, Car
    public string Type { get; set; }
    public string Brand { get; set; }
    public int Weight { get; set; }
}
Cetin Basoz
  • 22,495
  • 3
  • 31
  • 39
  • Very interesting! I tried to use the paste special XML to class in Visual Studio, but the data type was quite hard to use (for me as a beginner). Essentially it was a class containing different class arrays like public class Cars[]; I'll look into this later, thank you! – Cenderze Jun 24 '23 at 14:30
  • @Cenderze, for this type of xml, paste special is not a good option IMHO. – Cetin Basoz Jun 24 '23 at 18:47
0

You can use the following classes to deserialize this with XmlSerializer automatically

public class Carpark
{
    public List<Truck> Trucks { get; set; }
    public List<Car> Cars { get; set; }
    public List<Tractor> Tractors { get; set; }
}

[XmlInclude(typeof(Truck))]
[XmlInclude(typeof(Car))]
[XmlInclude(typeof(Tractor))]
public class Vehicle
{
    [XmlIgnore]
    public string Type => this.GetType().Name;
    
    [XmlAttribute("brand")]
    public string Brand { get; set; }
    
    [XmlAttribute("kg")]
    public int Weight { get; set; }
}

public class Truck : Vehicle
{
}

public class Car : Vehicle
{
}

public class Tractor : Vehicle
{
}

var cp = (Carpark)serializer.Deserialize(someStreamReader);

dotnetfiddle

Charlieface
  • 52,284
  • 6
  • 19
  • 43