简体   繁体   中英

XML serialization override dervied class name with XSI:Type

I am using following code for Student and Employee class derived from Person.

[XmlInclude(typeof(Student)), XmlInclude(typeof(Employee))]
public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Gender { get; set; }
}

[XmlType("Student")]
public class Student : Person
{
    public int StudentId { get; set; }
    public List<string> Subjects { get; set; }
}

[XmlType("Employee")]
public class Employee : Person
{
    public int EmployeeId { get; set; }
    public float Experience { get; set; }
}

I am creating a list of Person classes and initiate with following values and generating XML by serializing the same.

public class TestSerialization
{        
    List<Person> lstPerson = new List<Person>();

    public void XMLGen()
    {  

        Person obj = new Person() { Name = "Person1", Age = 10, Gender = "M" };
        Person obj2 = new Person() { Name = "Person2", Age = 10, Gender = "F" };

        Student objS = new Student()
        {
            Name = "Student1",
            Age = 20,
            Gender = "M",
            StudentId = 1,
            Subjects = new List<string>() { "Math", "Science" }
        };
        Student objS2 = new Student()
        {
            Name = "Student2",
            Age = 15,
            Gender = "F",
            StudentId = 1,
            Subjects = new List<string>() { "Physics", "Chemistry" }
        };

        Employee objE = new Employee()
        {
            Name = "Employee1",
            Age = 15,
            Gender = "F",
            EmployeeId = 1,
            Experience = 5.5f
        };

        Employee objE2 = new Employee()
        {
            Name = "Employee2",
            Age = 15,
            Gender = "M",
            EmployeeId = 2,
            Experience = 6.5f
        };

        lstPerson.Add(obj);
        lstPerson.Add(obj2);
        lstPerson.Add(objS);
        lstPerson.Add(objS2);
        lstPerson.Add(objE);
        lstPerson.Add(objE2);

        Type[] types = { typeof(Student), typeof(Employee) };

        XmlSerializer objXml = new XmlSerializer(typeof(List<Person>), types);

        using (StringWriter textWriter = new StringWriter())
        {
            objXml.Serialize(textWriter, lstPerson);
            string aa = textWriter.ToString();
        }

    }

}

But XML that generated contains derived class name as xsi:type="Student" and xsi:type="Employee" as shown below.

<Person xsi:type="Student">
<Name>Student1</Name>
<Age>20</Age>
<Gender>M</Gender>
<StudentId>1</StudentId>
<Subjects>
  <string>Math</string>
  <string>Science</string>
</Subjects>

and for Employee it is

<Person xsi:type="Employee">
<Name>Employee2</Name>
<Age>15</Age>
<Gender>M</Gender>
<EmployeeId>2</EmployeeId>
<Experience>6.5</Experience>

Is it possible the we get XML node name as Student,Employee rather than Person with xsi:type?

I want XML should be like this.

<Employee>
<Name>Employee2</Name>
<Age>15</Age>
<Gender>M</Gender>
<EmployeeId>2</EmployeeId>
<Experience>6.5</Experience>

The xsi:type is needed for deserialization, when you try to read from the XML again. Otherwise the deserializer wouldn't know what class to deserialize to.

If you are not planning to deserialize into a class again, then you could add your own custom serializer.

Adding xmlroot should give the root tag as employee. You cannot eliminate the type attribute because of the inheritance in the class structure.

    [XmlInclude(typeof(Student)), XmlInclude(typeof(Employee))]
    [XmlRoot("Employee")]
    public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public string Gender { get; set; }
    }

    [XmlType("Student")]
    public class Student : Person
    {
        public int StudentId { get; set; }
        public List<string> Subjects { get; set; }
    }

    [XmlType("Employee")]
    public class Employee : Person
    {
        public int EmployeeId { get; set; }
        public float Experience { get; set; }
    }

I got the solution from https://msdn.microsoft.com/en-us/library/3z3z5s6h%28v=vs.110%29.aspx link. Use XmlElementAttribute to change element name and add the XmlElementAttribute to a XmlAttributes instance. Then add the XmlAttributes to a XmlAttributeOverrides instance, specifying the type being overridden and the name of the member that accepts the derived class.

public class Orders
{
    public List<Person> Persons;
}

 public void SerializeObject(string filename)
    {
        // Each overridden field, property, or type requires 
        // an XmlAttributes instance.
        XmlAttributes attrs = new XmlAttributes();

        // Creates an XmlElementAttribute instance to override the 
        // field that returns Book objects. The overridden field
        // returns Expanded objects instead.
        XmlElementAttribute attr = new XmlElementAttribute();
        attr.ElementName = "Student";
        attr.Type = typeof(Student);

        XmlElementAttribute attrE = new XmlElementAttribute();
        attrE.ElementName = "Employee";
        attrE.Type = typeof(Employee);

        // Adds the element to the collection of elements.
        attrs.XmlElements.Add(attr);
        attrs.XmlElements.Add(attrE);

        // Creates the XmlAttributeOverrides instance.
        XmlAttributeOverrides attrOverrides = new XmlAttributeOverrides();

        // Adds the type of the class that contains the overridden 
        // member, as well as the XmlAttributes instance to override it 
        // with, to the XmlAttributeOverrides.
        attrOverrides.Add(typeof(Orders), "Persons", attrs);

        // Creates the XmlSerializer using the XmlAttributeOverrides.
        XmlSerializer s =
        new XmlSerializer(typeof(Orders), attrOverrides);

During serialization, it will use override attributes to overrride their properties.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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