Search code examples
c#xml-serializationdatacontractserializer

How to implement Custom XML Serialization in C#


Below is the my XML file.

<Employee>
    <FirstName>#{FirstName}#</FirstName>
    <LastName>#{LastName}#</LastName>
    <DOB>#{DOB}#</DOB>
    <Address>#{Address}#</Address>
    <Transcation>
        <Month>#{Month}#</Month>
        <Amount>#{Amount}#</Amount>
    </Transcation>
    <Transcation>
        <Month>#{Month}#</Month>
        <Amount>#{Amount}#</Amount>
    </Transcation>
    <Transcation>
        <Month>#{Month}#</Month>
        <Amount>#{Amount}#</Amount>
    </Transcation>
    <Transcation>
        <Month>#{Month}#</Month>
        <Amount>#{Amount}#</Amount>
    </Transcation>

and my serializable class is

[XmlRoot("Employee"), Serializable]    
 public class Employee    
 {    
     [XmlAnyElement]
      public List<XmlElement> EmployeeDetails    { get; set; }
 }

But i want to get something like this

In my EmployeeDetails i should serialize only FirstName, LastName, DOB, Address,.... and I should get List of Transcation in a separate class which contains Month and Amount as serialiazable element.

something like this

[XmlRoot("Employee"), Serializable]    
public class Employee    
{    
 [XmlAnyElement]
 public List<XmlElement> EmployeeDetails    { get; set; }

 [XmlElement("Transcation")]
 public List<Transcation> Transcations { get; set; }

}

public class Transcation
{
  [XmlElement("Month")]
    public string Month{ get; set; }
  [XmlElement("Amount")]
    public string Amount{ get; set; }

}

How can i do this ?


Solution

  • Assuming you can't modify the XML your class should look like the following. XmlAnyElement can be used however you will probably need to set it as an object array. So your code should look like this:

    [XmlRoot("Employee"), Serializable]
    public class Employee
    {
        [XmlAnyElement]
        public XmlElement [] EmployeeDetails { get; set; }
    
        [XmlElement("Transcation")]
        public List<Transaction> Transcations { get; set; }
    }
    

    To Deserialize you do the following:

        private void DeserializeObject(string filename)
        {
            XmlAnyElementAttribute myAnyElement = new XmlAnyElementAttribute();
            XmlAttributeOverrides xOverride = new XmlAttributeOverrides();
            XmlAttributes xAtts = new XmlAttributes();
            xAtts.XmlAnyElements.Add(myAnyElement);
            xOverride.Add(typeof(Employee), "EmployeeDetails", xAtts);
    
            XmlSerializer ser = new XmlSerializer(typeof(Employee), xOverride);
    
            FileStream fs = new FileStream(filename, FileMode.Open);
            var g = (Employee)ser.Deserialize(fs);
            fs.Close();
    
            Console.WriteLine(g.EmployeeDetails.Length);
            foreach (XmlElement xelement in g.EmployeeDetails)
            {
                Console.WriteLine(xelement.Name + ": " + xelement.InnerXml);
            }
        }
    

    I recommend instead to specify the properties, it will make it easier to look for specific values. But this depends on what you know about the xml schema before hand.

    [XmlRoot(ElementName="Employee")]    
    public class Employee    
    {    
      [XmlElement(ElementName="FirstName")]    
      public string FirstName {get;set;}
    
      [XmlElement(ElementName="LastName")]
      public string LastName {get;set;}
    
      [XmlElement(ElementName="DOB")]
      public DateTime DOB {get;set;}
    
      [XmlElement(ElementName="Address")]
      public string Address {get;set;}
    
      [XmlElement(ElementName="Transaction")]
      public List<Transaction> Transaction {get;set;}
    }
    
    
    [XmlRoot(ElementName="Transaction")]
    public class Transaction
    {
    
      [XmlElement(ElementName="Month")]
      public int Month {get;set;}
    
      [XmlElement(ElementName="Amount")]
      public int Amount {get;set;}
    }