将 xml 反序列化为从基础 class 继承的 classes

deserialize xml into inherited classes from base class

我有以下 xml 结构:

<Root1>
    <name>Name1</name>
    <company>Comp1</company>
    <url>site.com</url>
    <elements>
        <element id="12" type="1">
            <url>site1.com</url>
            <price>15000</price>
            ...
            <manufacturer_warranty>true</manufacturer_warranty>
            <country_of_origin>Япония</country_of_origin>
        </element>
        <element id="13" type="2">
            <url>site2.com</url>
            <price>100</price>
            ...
            <language>lg</language>
            <binding>123</binding>
        </element>
    </elements>
</Root1>

我需要将这个 xml 反序列化为一个对象。您可以看到该元素包含一些等于字段:urlprice。 我想将这些字段移动到父 class 中,然后从其他 classes 继承这个 class。

我创建了 class Root1:

namespace app1
{
    [Serializable]
    public class Root1
    {
        [XmlElement("name")] 
        public string Name { get; set; }

        [XmlElement("company")] 
        public string Company { get; set; }

        [XmlElement("url")] 
        public string Url { get; set; }

        [XmlElement("elements")]
        public List<Element> ElementList { get; set; }
    }
}

然后我为 Element 创建了基础 class:

[Serializable]
    public class Element
    {
        [XmlElement("url")] 
        public string Url { get; set; }

        [XmlElement("price")] 
        public string Price { get; set; }
    }

然后我从其他class继承了这个class:

[Serializable]
public class Element1 : Element
{
    [XmlElement("manufacturer_warranty")] 
    public string mw { get; set; }

    [XmlElement("country_of_origin")] 
    public string co { get; set; }
}

[Serializable]
public class Element2 : Element
{
    [XmlElement("language")] 
    public string lg { get; set; }

    [XmlElement("binding")] 
    public string bind { get; set; }
}

当我将此 xml 反序列化为对象 Root1 时,我得到了对象 - 没问题。 但是 Elements 的列表只包含 Element 个对象而不是 Element1Element2 个对象。

我如何反序列化此 xml 以便 Elements 的列表包含 Element1Element2 对象?

我认为你应该这样使用 XmlIncludeAttribute

[XmlInclude(typeof(Element1))]
public class Element
{
}

这是xml和代码。我喜欢先用测试数据序列化,然后反序列化。

<?xml version="1.0" encoding="utf-8"?>
<Root1>
  <name>Name1</name>
  <company>Comp1</company>
  <url>site.com</url>
  <element d2p1:type="Element1" xmlns:d2p1="http://www.w3.org/2001/XMLSchema-instance">
    <url>site1.com</url>
    <price>15000</price>
    <manufacturer_warranty>true</manufacturer_warranty>
    <country_of_origin>Япония</country_of_origin>
  </element>
  <element d2p1:type="Element2" xmlns:d2p1="http://www.w3.org/2001/XMLSchema-instance">
    <url>site2.com</url>
    <price>100</price>
    <language>lg</language>
    <binding>123</binding>
  </element>
</Root1>

代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.IO;


namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string FILENAME = @"c:\temp\test.xml";
            Root1 root1 = new Root1() {
                Name = "Name1",
                Company = "Comp1",
                Url = "site.com",
                ElementList = new List<Element>() {
                    new Element1() {
                        Url = "site1.com",
                        Price = "15000",
                        mw = "true",
                        co = "Япония"
                    },
                    new Element2() {
                        Url = "site2.com",
                        Price = "100",
                        lg = "lg",
                        bind = "123"
                    }
                }
            };

            XmlSerializer serializer = new XmlSerializer(typeof(Root1));
            StreamWriter writer = new StreamWriter(FILENAME);
            XmlSerializerNamespaces _ns = new XmlSerializerNamespaces();
            _ns.Add("", "");
            serializer.Serialize(writer, root1, _ns);
            writer.Flush();
            writer.Close();
            writer.Dispose();

            XmlSerializer xs = new XmlSerializer(typeof(Root1));
            XmlTextReader reader = new XmlTextReader(FILENAME);
            Root1 newRoot1 = (Root1)xs.Deserialize(reader);


        }

    }
    [XmlRoot("Root1")]
    public class Root1
    {
        [XmlElement("name")]
        public string Name { get; set; }

        [XmlElement("company")]
        public string Company { get; set; }

        [XmlElement("url")]
        public string Url { get; set; }

        [XmlElement("element")]
        public List<Element> ElementList { get; set; }
    }
    [XmlInclude(typeof(Element1))]
    [XmlInclude(typeof(Element2))]
    [XmlRoot("element")]
    public class Element
    {
        [XmlElement("url")]
        public string Url { get; set; }

        [XmlElement("price")]
        public string Price { get; set; }
    }
    [XmlRoot("element1")]
    public class Element1 : Element
    {
        [XmlElement("manufacturer_warranty")]
        public string mw { get; set; }

        [XmlElement("country_of_origin")]
        public string co { get; set; }
    }

    [XmlRoot("element2")]
    public class Element2 : Element
    {
        [XmlElement("language")]
        public string lg { get; set; }

        [XmlElement("binding")]
        public string bind { get; set; }
    }



}

下面的代码与您发布的 XML 更匹配。您需要将生成的 xml 与您的 xml.

进行比较
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.IO;


namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string FILENAME = @"c:\temp\test.xml";
            Root1 root1 = new Root1()
            {
                Name = "Name1",
                Company = "Comp1",
                Url = "site.com",
                cElement = new Elements() { 
                   ElementList = new List<Element>() {
                       new Element1() {
                           Url = "site1.com",
                           Price = "15000",
                           mw = "true",
                           co = "Япония"
                       },
                       new Element2() {
                           Url = "site2.com",
                           Price = "100",
                           lg = "lg",
                           bind = "123"
                       }
                    }

                }
            };

            XmlSerializer serializer = new XmlSerializer(typeof(Root1));
            StreamWriter writer = new StreamWriter(FILENAME);
            XmlSerializerNamespaces _ns = new XmlSerializerNamespaces();
            _ns.Add("", "");
            serializer.Serialize(writer, root1, _ns);
            writer.Flush();
            writer.Close();
            writer.Dispose();

            XmlSerializer xs = new XmlSerializer(typeof(Root1));
            XmlTextReader reader = new XmlTextReader(FILENAME);
            Root1 newRoot1 = (Root1)xs.Deserialize(reader);

        }

    }
    [XmlRoot("Root1")]
    public class Root1
    {
        [XmlElement("name")]
        public string Name { get; set; }

        [XmlElement("company")]
        public string Company { get; set; }

        [XmlElement("url")]
        public string Url { get; set; }

        [XmlElement("elements")]
        public Elements cElement { get; set; }
    }

    [XmlRoot("elements")]
    public class Elements
    {
        [XmlElement("element")]
        public List<Element> ElementList { get; set; }
    }

    [XmlInclude(typeof(Element1))]
    [XmlInclude(typeof(Element2))]
    [XmlRoot("element", Namespace = "")]
    public class Element
    {
        [XmlElement("url")]
        public string Url { get; set; }

        [XmlElement("price")]
        public string Price { get; set; }
    }
    [XmlRoot("element1", Namespace = "")]
    public class Element1 : Element
    {
        [XmlElement("manufacturer_warranty")]
        public string mw { get; set; }

        [XmlElement("country_of_origin")]
        public string co { get; set; }
    }

    [XmlRoot("element2", Namespace = "")]
    public class Element2 : Element
    {
        [XmlElement("language")]
        public string lg { get; set; }

        [XmlElement("binding")]
        public string bind { get; set; }
    }

}​

@netwer 它不适合你,因为上面建议的代码生成的 xml(下面)与你用于反序列化的代码不匹配(看看它如何在 for 元素中指定派生类型) .

<?xml version="1.0" encoding="utf-8"?>
<Root1>
  <name>Name1</name>
  <company>Comp1</company>
  <url>site.com</url>
  <elements>
    <element d3p1:type="Element1" xmlns:d3p1="http://www.w3.org/2001/XMLSchema-instance">
      <url>site1.com</url>
      <price>15000</price>
      <manufacturer_warranty>true</manufacturer_warranty>
      <country_of_origin>Япония</country_of_origin>
    </element>
    <element d3p1:type="Element2" xmlns:d3p1="http://www.w3.org/2001/XMLSchema-instance">
      <url>site2.com</url>
      <price>100</price>
      <language>lg</language>
      <binding>123</binding>
    </element>
  </elements>
</Root1>

因此,您必须将此格式与源 xml 匹配(更改代码或 API returns 此 xml 数据)或采用其他方法。即使您设法使用前一个,您也必须找到一种方法来访问 Element1 或 Element2 的特定属性。

newRoot1.Elements.ElementList[i] 将始终只允许您访问价格和 url,因为您的列表是元素类型。尽管 运行 ElementList[i] 的时间类型将是 Element1 或 Element2,您将如何检测?

这里我建议另一种方法。无论您的应用程序(客户端)是否生成此 xml 或服务器 returns 它在点击 API 时生成,您都应该能够收集适用于 [=20] 的所有字段的信息=] 对象。如果它是您的代码,您已经知道它,如果它是 API,则必须有它的文档。这样你只需要创建一个 'Element'(没有派生的 classes)并在访问元素 class 属性 之前进行适当的检查(主要是 string.IsNullOrEmpty())代码中的值。只有 xml 'element' 元素中存在的属性才会被视为剩余的,对于该实例将被设置为 NULL。

[Serializable]
public class Element
{
   [XmlElement("url")]
   public string Url { get; set; }

   [XmlElement("price")] 
   public string Price { get; set; }

   [XmlElement("manufacturer_warranty")]
   public string mw { get; set; }

   [XmlElement("country_of_origin")]
   public string co { get; set; }

   [XmlElement("language")]
   public string lg { get; set; }

   [XmlElement("binding")]
   public string bind { get; set; }
}