将XML反序列化为基类的继承类

本文关键字:继承 基类 XML 反序列化 | 更新日期: 2023-09-27 18:05:44

我有以下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。我想把这些字段移到父类中,然后从其他类继承这个类。

创建类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创建基类:

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

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

[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的List只包含Element对象,不包含Element1Element2对象。

我如何反序列化这个xml,使Elements列表包含Element1Element2对象?

将XML反序列化为基类的继承类

@netwer这对您不起作用,因为上面建议的代码生成的xml(下面)与您用于反序列化的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(更改返回此xml数据的代码或API)匹配,要么采用另一种方法。即使您设法使用前一个,您也必须找到一种方法来访问Element1或Element2特定的属性。

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

这里我建议另一种方法。无论您的应用程序(客户端)生成该xml还是服务器在访问API时返回该xml,您都应该能够收集适用于"元素"对象的所有字段的信息。如果它是你的代码,你已经知道它了,如果它是一个API,那么它必须有一个文档。这样,您只需要创建一个'Element'(没有派生类)并在访问代码中的Element类属性值之前进行适当的检查(主要是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; }
}

我认为你应该这样使用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; }
    }
}​