1

I would like to generate an XML using XMLSerializer. I have an abstract Base class which is being inherited by other classes.

 public abstract class Base
    {
      public string Name {get; set;}
      public int ID {get; set;}

      public Base(string Name, int ID)
      {
         this.Name = Name;
         this.ID = ID;
      }
    }



 public class HR: Base
    {      
      public HR(string Name, int ID): Base(Name,ID)
      {
      }
    }

    public class IT : Base
    {
      public IT(string Name, int ID): Base(Name,ID)
      {
      }
    }

I am not sure how to generate an XML of format

<Employee>
 <HR>
  <Name> </Name>
  <ID> </ID>
 </HR>
 <IT>
  <Name> </Name>
  <ID> </ID>
 </IT>
</Employee>

I apologise for the vague question. I have never used XMLSerializer before and not sure how to proceed with it. Any help would be greatly appreciated.

Thanks

Sugan88
  • 313
  • 1
  • 4
  • 21
  • There are some other errors with your classes. You define `ID` as being a `string` in your `Employee` base class, yet inside the `HR` class and the `IT` class, you pass along a `int` as ID. Also, to make a call to the base class, you should do `base(Name, ID)` instead of `Employee(Name, ID)`. – nbokmans Aug 22 '17 at 09:07
  • @nbokmans Apologies. That was just a typo. I have edited and updated the code now. Thanks for pointing it out. – Sugan88 Aug 22 '17 at 09:12
  • For Xml Serializer to work your classes has to have public parametless constructor. – Ondrej Svejdar Aug 22 '17 at 09:59

3 Answers3

1

Add the [Serializable] Annotation to the class you want to serialize.

        [System.Serializable]
        public class Base
        {
        public string Name { get; set; }
        public int ID { get; set; }

        public Base(string Name, int ID)
            {
            this.Name = Name;
            this.ID = ID;
            }
        }

To serialize in XML format, use the following code:

        System.Xml.Serialization.XmlSerializer Serializer = new System.Xml.Serialization.XmlSerializer(typeof(Base));
        Base Foo = new Base();
        string xmldata = "";

        using (var stringwriter = new System.IO.StringWriter())
        {
            using (System.Xml.XmlWriter xmlwriter = System.Xml.XmlWriter.Create(stringwriter))
            {
                Serializer.Serialize(xmlwriter, Foo);
                xml = stringwriter.ToString(); // Your XML
            }
        }

To deserialize from XML back to your Base object, use the following code:

        System.IO.MemoryStream FooStream = new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(xml));
        Base Foo;
        Foo = (Base)Serializer.Deserialize(FooStream);
Afnan Makhdoom
  • 654
  • 1
  • 8
  • 20
  • Thank you very much! Employee Foo = new Employee() would throw an error because I think its not possible to create an instance of an abstract class? – Sugan88 Aug 22 '17 at 09:24
  • You will need a default constructor in your class for the serializer to work and a concrete type. – mahlatse Aug 22 '17 at 09:28
  • I am so sorry, I didn't read the abstract part first, you can't create an instance of an abstract class, true. But your question inherently revolved around its serialization meaning you would have an object, the above code works well for serializing created objects – Afnan Makhdoom Aug 22 '17 at 09:39
1

I think you need to use the XmlType attributes to make sure your elements show up as <HR> and <IT> instead of <employee xsi:type="HR">. Working demo below:

public abstract class Employee
{
    public string Name { get; set; }
    public string ID { get; set; }

    public Employee(string Name, string ID)
    {
        this.Name = Name;
        this.ID = ID;
    }
}

public class HR : Employee
{
    public HR(string Name, string ID) : base(Name, ID)
    {
    }


    public HR() : base("No name", "No ID")
    {

    }
}

public class IT : Employee
{
    public IT(string Name, string ID) : base(Name, ID)
    {
    }

    public IT() : base("No name", "No ID")
    {

    }
}   

I added default (parameter-less) constructors for the serializer.

Then you have to have some kind of wrapper object to handle a list of Employees:

public class Employees
{
    [XmlElement(typeof(IT))]
    [XmlElement(typeof(HR))]
    public List<Employee> Employee { get; set; } //It doesn't really matter what this field is named, it takes the class name in the serialization
}

Next, you can use the serializer code from my comment to generate the XML:

var employees = new Employees
{
    Employee = new List<Employee>()
    {
        new IT("Sugan", "88"),
        new HR("Niels", "41")
    }
};

var serializer = new XmlSerializer(typeof(Employees));
var xml = "";

using (var sw = new StringWriter())
{
    using (XmlWriter writer = XmlWriter.Create(sw))
    {
        serializer.Serialize(writer, employees);
        xml = sw.ToString();
    }
}
Console.WriteLine(xml);

(Namespaces ommitted for clarity's sake)

This returns the following XML:

<?xml version="1.0" encoding="UTF-8"?>
<Employees xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <IT>
      <Name>Sugan</Name>
      <ID>88</ID>
   </IT>
   <HR>
      <Name>Niels</Name>
      <ID>41</ID>
   </HR>
</Employees>
nbokmans
  • 5,492
  • 4
  • 35
  • 59
1

As I read your xml, it seems you want to serialize a list of Employee. I have a solution for you if your list is a member of a class (not directly serializing the list).

public abstract class Employee
{
    public string Name { get; set; }
    public int ID { get; set; }
    public Employee(string Name, int ID)
    {
        this.Name = Name;
        this.ID = ID;
    }
}

public class HR : Employee
{
    public HR() : base(null, 0) { } // default constructor is needed for serialization/deserialization
    public HR(string Name, int ID) : base(Name, ID) { }
}
public class IT : Employee
{
    public IT() : base(null, 0) { }
    public IT(string Name, int ID) : base(Name, ID) { }
}

public class Group
{
    [XmlArray("Employee")]
    [XmlArrayItem("HR",typeof(HR))]
    [XmlArrayItem("IT",typeof(IT))]
    public List<Employee> list { get; set; }

    public Group()
    {
        list = new List<Employee>();
    }
}
class Program
{
    static void Main(string[] args)
    {
        Group grp = new Group();
        grp.list.Add(new HR("Name HR", 1));
        grp.list.Add(new IT("Name IT", 2));

        XmlSerializer ser = new XmlSerializer(typeof(Group));
        ser.Serialize(Console.Out, grp);
    }
}

And the output is :

<?xml version="1.0" encoding="ibm850"?>
<Group xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Employee>
    <HR>
      <Name>Name HR</Name>
      <ID>1</ID>
    </HR>
    <IT>
      <Name>Name IT</Name>
      <ID>2</ID>
    </IT>
  </Employee>
</Group>

Very similar to your desired output, excepted one more element at the root "Group".

Deserialize with the same XmlSerializer(typeof(Group)) should work as well.

Pascal
  • 142
  • 3