Reputation: 23
I have one XML file called VehicleInfo. I want to deserialize VehicleInfo in List of Vehicle. Now I have one base class called Vehicle and three derived class named as Car, Bike, Truck. How to deserialize specific object of vehicle based on value of Vehicle node in xml. (ex. if node value is Car than object of car should be stored in List of vehicle)
<Vehicles>
<Vehicle>Car</Vehicle>
<Vehicle>Bike</Vehicle>
<Vehicle>Truck</Vehicle>
</Vehicles>
For example,
VehicleList class :
public class VehicleList
{
List<Vehicle> lstVehicles = new List<Vehicle>();
}
Vehicle class :
public class Vehicle
{
public string name = "Vehicle";
}
Car class :
public class Car : Vehicle
{
public Car()
{
name = "Car";
}
}
Bike class :
public class Bike : Vehicle
{
public Bike()
{
name = "Bike";
}
}
Truck class :
public class Truck : Vehicle
{
public Truck()
{
name = "Truck";
}
}
This Vehicle program is just example,
So, How can I deserialize specific object (Such as Car, Bike, or Truck) in List of Vehicle in VehicleList class based on value of node Vehicle.
Upvotes: 2
Views: 934
Reputation: 3241
Ok, this is going to be long...
You can play with this solution .net-fiddle-here
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml.Serialization;
public class Program
{
public static void Main()
{
var root = new Vehicles
{
Items =
{
new Vehicle() { Name = "Car"},
new Vehicle() { Name = "Truck"},
new Vehicle() { Name = "Bike"}
}
};
var xmlSerializer = new XmlSerializer(typeof(Vehicles));
var memoryStream = new MemoryStream();
TextWriter stringWriter = new StreamWriter(memoryStream, System.Text.Encoding.UTF8);
xmlSerializer.Serialize(stringWriter, root);
string xml = System.Text.Encoding.UTF8.GetString(memoryStream.ToArray());
//Make XML
var obj = root;
var xmlString = obj.XmlSerializeToString();
//Make Object with Direct Deserialization
var vehicles = xmlString.XmlDeserializeFromString<Vehicles>();
//Make polymorphic object from generic vehicles with some "logic"
var polymorphicVehicles = new List<Vehicle>(); // ****** THIS is the collection you requested!!!! *********
// iterate over all vehicles
foreach (var item in vehicles.Items)
{
// use json serialization, because casting Parent to Child is not acceptable
var jsonVehicle = JsonConvert.SerializeObject(item);
// depending on the Name of the vehicle, create a corresponding object
switch (item.Name)
{
case "Car":
var aCar = JsonConvert.DeserializeObject<Car>(jsonVehicle);
polymorphicVehicles.Add(aCar);
break;
case "Truck":
var aTruck = JsonConvert.DeserializeObject<Truck>(jsonVehicle);
polymorphicVehicles.Add(aTruck);
break;
case "Bike":
var aBike = JsonConvert.DeserializeObject<Bike>(jsonVehicle);
polymorphicVehicles.Add(aBike);
break;
default:
break;
}
}
// this is just to print it out!
var jsonPolymorphicVehicles = JsonConvert.SerializeObject(polymorphicVehicles);
Console.WriteLine("XML:");
Console.WriteLine(xml);
Console.WriteLine("");
Console.WriteLine("Polymorphic to jason");
Console.WriteLine(jsonPolymorphicVehicles);
Console.WriteLine("");
Console.WriteLine("Press key to exit!");
Console.Read();
}
}
public class Vehicle
{
public string Name = "Vehicle";
}
public class Car : Vehicle
{
public Car()
{
Name = "Car";
}
}
public class Bike : Vehicle
{
public Bike()
{
Name = "Bike";
}
}
public class Truck : Vehicle
{
public Truck()
{
Name = "Truck";
}
}
public class Vehicles
{
public List<Vehicle> Items { get; } = new List<Vehicle>();
}
public static class MyStaticClass
{
public static T XmlDeserializeFromString<T>(this string objectData)
{
return (T)XmlDeserializeFromString(objectData, typeof(T));
}
public static string XmlSerializeToString(this object objectInstance)
{
var serializer = new XmlSerializer(objectInstance.GetType());
var sb = new StringBuilder();
using (TextWriter writer = new StringWriter(sb))
{
serializer.Serialize(writer, objectInstance);
}
return sb.ToString();
}
public static object XmlDeserializeFromString(this string objectData, Type type)
{
var serializer = new XmlSerializer(type);
object result;
using (TextReader reader = new StringReader(objectData))
{
result = serializer.Deserialize(reader);
}
return result;
}
}
Upvotes: 0
Reputation: 34419
Here is code and results to serialize. XML you cannot have an array as a root element. So in this case it make sense to have two classes : Vehicles and Vehicle. See code below :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
namespace ConsoleApplication107
{
class Program
{
const string FILENAME = @"c:\temp\test.xml";
static void Main(string[] args)
{
Vehicles vehicles = new Vehicles()
{
vehicles = new List<Vehicle>() {
new Car() { make = "BMW"},
new Bike() { make = "Buffalo"},
new Truck() { make = "MAC"}
}
};
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
XmlWriter writer = XmlWriter.Create(FILENAME, settings);
XmlSerializer serializer = new XmlSerializer(typeof(Vehicles));
serializer.Serialize(writer, vehicles);
}
}
public class Vehicles
{
[XmlElement("Vehicle")]
public List<Vehicle> vehicles { get; set; }
}
[XmlInclude(typeof(Car))]
[XmlInclude(typeof(Bike))]
[XmlInclude(typeof(Truck))]
public class Vehicle
{
public string make { get; set; }
}
public class Car : Vehicle
{
}
public class Bike : Vehicle
{
}
public class Truck : Vehicle
{
}
}
Here is results :
<?xml version="1.0" encoding="utf-8"?>
<Vehicles xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Vehicle xsi:type="Car">
<make>BMW</make>
</Vehicle>
<Vehicle xsi:type="Bike">
<make>Buffalo</make>
</Vehicle>
<Vehicle xsi:type="Truck">
<make>MAC</make>
</Vehicle>
</Vehicles>
Upvotes: 1
Reputation: 1062915
XmlSerializer
supports some kinds of inheritance modelling, but: it is based on the elements/attributes, not the actual values; I'm not aware of any API that would support what you want from that data, so you'll have to deserialize them as strings, and post-process them to what you want.
An example of something that would be possible is:
<Vehicles>
<Car>...car things...</Car>
<Bike>...bike things...</Bike>
<Truck>...truck things...</Truck>
</Vehicles>
which can be achieved via:
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
[XmlInclude(typeof(Car))] // technically you only need XmlInclude
[XmlInclude(typeof(Bike))] // if you're using xsi:type resolution
[XmlInclude(typeof(Truck))] // but... it doesn't hurt us here
public abstract class Vehicle { }
public class Car : Vehicle { }
public class Truck : Vehicle { }
public class Bike : Vehicle { }
[XmlRoot("Vehicles")]
public class MyRoot
{
[XmlElement("Car", Type = typeof(Car))]
[XmlElement("Truck", Type = typeof(Truck))]
[XmlElement("Bike", Type = typeof(Bike))]
public List<Vehicle> Items { get; } = new List<Vehicle>();
}
static class P
{
static void Main()
{
var root = new MyRoot
{
Items =
{
new Car(),
new Bike(),
new Truck(),
}
};
var ser = new XmlSerializer(typeof(MyRoot));
var ns = new XmlSerializerNamespaces();
ns.Add("", "");
ser.Serialize(Console.Out, root, ns);
}
}
Upvotes: 0