Reputation: 1767
I have a XML from a 3rd party software that I have to deserialize, but I have the spec of the XML.
At a certain point I have a node that contains a bunch of different Nodes of different types. I have to deserialize this Node (Vehicles) as a list. Each of the child nodes is one subclass of the class Vehicle
public List<Vehicle> Vehicles = new List<Vehicles>();
the definition of the class is as following
public class Vehicle
{
public string Vehicletype { get; set; }
public virtual bool Drive() { return true; }
}
public class Car:Vehicle
{
public int NumberOfDoors { get; set; }
public override bool Drive() { return false; }
}
public class Boat:Vehicle
{
public int NumberOfSeats { get; set; }
}
The definition of the XML looks like this
<vehicles>
<car NumberOfDoors="4" />
<car NumberOfDoors="3" />
<boat NumberOfSeats="1024" />
<boat NumberOfSeats="20" />
<car NumberOfDoors="5" />
</vehicles>
At a certain point I have to loop through them and let them "Drive". I don't have the experience With XMLSchema definitions. Now I am using The vehicleType in a factory and some other things. It's basically becoming a mess.
I would need a suggestion how to let the Serializer do this instead of me. I doubt that I am the first one to have this issue.
Upvotes: 2
Views: 121
Reputation: 116794
Firstly, you have to mark NumberofSeats
and NumberOfDoors
with the XmlAttribute
attribute to tell XmlSerializer
that these properties should appear as XML attributes:
public class Car : Vehicle
{
[XmlAttribute]
public int NumberOfDoors { get; set; }
public override bool Drive() { return false; }
}
public class Boat : Vehicle
{
[XmlAttribute]
public int NumberOfSeats { get; set; }
}
Next, if <vehicles>
appears as an XML Node inside some containing root element, you can make your public List<Vehicle> Vehicles
appear as a member inside the corresponding container class, and apply an XmlArray
attribute to it to indicate that the list should be serialized in two levels, and XmlArrayItem
attributes to inform XmlSerializer
of the possible of vehicles that might be encountered in the list along with the start tag to use for each:
public class VehiclesContainer // Your container class
{
[XmlArray("vehicles")]
[XmlArrayItem("vehicle", typeof(Vehicle))]
[XmlArrayItem("car", typeof(Car))]
[XmlArrayItem("boat", typeof(Boat))]
public List<Vehicle> Vehicles = new List<Vehicle>();
}
On the other hand, <vehicles>
is the root node of the XML document and there is no containing node, you can introduce a root node class containing the list of vehicles, then apply multiple XmlElement
attributes to indicate that the list should be serialized in one level rather than two along with the start tag to use for each possible vehicle type:
[XmlRoot("vehicles")]
public class VehicleList
{
[XmlElement("vehicle", typeof(Vehicle))]
[XmlElement("car", typeof(Car))]
[XmlElement("boat", typeof(Boat))]
public List<Vehicle> Vehicles = new List<Vehicle>();
}
Having done this, XmlSerializer
will automatically deserialize your class hierarchy.
For more information, see here.
Upvotes: 2