如何基于xml节点的值将子对象反序列化为父列表(例如,List <parent>)?

时间:2019-04-05 09:43:43

标签: c# deserialization

我有一个名为VehicleInfo的XML文件。 我想反序列化Vehicle List中的VehicleInfo。 现在,我有一个称为“车辆”的基本类,还有三个名为“汽车”,“自行车”,“卡车”的派生类。 如何基于xml中Vehicle节点的值反序列化车辆的特定对象。 (例如,如果节点值为Car,则应将车辆的对象存储在车辆列表中)

<Vehicles>
    <Vehicle>Car</Vehicle>
    <Vehicle>Bike</Vehicle>
    <Vehicle>Truck</Vehicle>
</Vehicles>

例如,

VehicleList类:

public class VehicleList
{
    List<Vehicle> lstVehicles = new List<Vehicle>();
}

车辆类别:

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";
    }
}

这个Vehicle程序只是示例,

因此,如何基于节点Vehicle的值反序列化VehicleList类中的Vehicle List中的特定对象(例如,汽车,自行车或卡车)。

3 个答案:

答案 0 :(得分:1)

这里是要序列化的代码和结果。 XML不能将数组作为根元素。因此,在这种情况下,有两类是有意义的:车辆和车辆。参见下面的代码:

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
    {
    }
}

以下是结果:

<?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>

答案 1 :(得分:0)

XmlSerializer支持某些继承建模,但是:它基于元素 / 属性,而不是实际值;我不知道有任何API可以支持您从数据中获取所需的 ,因此您必须将它们反序列化为字符串,然后将其后处理为所需的内容。

可能可能发生的事情的示例是:

<Vehicles>
    <Car>...car things...</Car>
    <Bike>...bike things...</Bike>
    <Truck>...truck things...</Truck>
</Vehicles>

可以通过以下方式实现:

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);
    }
}

答案 2 :(得分:0)

好,这会很长...

您可以使用此解决方案.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!!!! *********

        // itterate 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;
    }
}