deserialize xml into inherited classes from base class

时间:2015-07-31 20:06:39

标签: c# xml xml-deserialization

I have the following xml structure:

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

I need to deserialize this xml into an object. You can see the element contains some equals field: url and price. I would like to move these fields into a parent class and then inherit this class from other classes.

I created the 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; }
    }
}

and then I created base class for Element:

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

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

and then I inherited this class from other classes:

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

When I deserialize this xml to object Root1 I get the object - it is ok. But the List of Elements contains only Element objects not Element1 and Element2 objects.

How I do deserialize this xml so list of Elements contains Element1 and Element2 objects?

4 个答案:

答案 0 :(得分:1)

I think you should use XmlIncludeAttribute like this:

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

答案 1 :(得分:1)

这是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; }
    }



}

答案 2 :(得分:1)

下面的代码与您发布的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; }
    }

}​

答案 3 :(得分:1)

@netwer它不适合您,因为上面建议的代码生成的xml(下面)与您用于反序列化的代码不匹配(请参阅它如何为元素指定派生类型)。

<?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]将始终只允许您访问价格和网址,因为您的列表是元素类型。虽然ElementList [i]的运行时类型将是Element1或Element2,但您将如何检测到它?

在这里,我建议替代方法。无论您的应用程序(客户端)是否生成此xml,还是在命中API时返回它的服务器,您都应该能够收集适用于“元素”的所有字段的信息。宾语。如果它是您已经知道的代码,如果它是API,则必须有一个文档。这样你只需要创建一个元素&#39; (没有派生类)并在访问代码中的Element类属性值之前进行适当的检查(主要是string.IsNullOrEmpty())。只有xml&#39;元素中存在的属性才会出现。将认为该元素的rest将被设置为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; }
}