繁体   English   中英

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

[英]How to deserialize child object into list of parent (ex, List<Parent>) based on values of xml nodes?

我有一个名为 VehicleInfo 的 XML 文件。 我想在车辆列表中反序列化 VehicleInfo。 现在我有一个名为 Vehicle 的基类和三个名为 Car、Bike、Truck 的派生类。 如何根据xml中Vehicle节点的值反序列化车辆的特定对象。 (例如,如果节点值为 Car,则汽车的对象应存储在车辆列表中)

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

例如,

车辆列表类:

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 类中的车辆列表中的特定对象(例如汽车、自行车或卡车)。

这是要序列化的代码和结果。 XML 不能将数组作为根元素。 所以在这种情况下,有两个类是有意义的:Vehicles 和 Vehicle。 见下面的代码:

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>

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

好吧,这会很长……

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM