Search code examples
c#.netxml-serialization

Serialize Property as Xml Attribute in new Element


I have a sipmle class

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Address Address { get; set; }

    public ICollection<Address> AllAddress { get; set; }
}

public class Address
{
    public string  Street { get; set; }
}

If i serialize People instance uses default XmlSerializer then i will get

<Person xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <Id>2</Id>
    <Name>FIO FIO IFO</Name>
    <Address>
        <Street>Golden Gate</Street>
    </Address>
</Person>

How do I get this result?

<struct n="People">
     <attr n="id">2</attr >
     <attr n="name">FIO FIO IFO</attr >
     <struct n="Address">
         <attr n="street">Golden Gate</attr>
     </struct >
</struct>

Solution

  • It seems you have to convert your xml to custom format so you have to implement IXmlSerializable interface in your Person class object like.

    public class Person : IXmlSerializable
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public Address Address { get; set; }
    
        public XmlSchema GetSchema() { throw new NotImplementedException(); }
    
        public void ReadXml(XmlReader reader)
        {
            while (reader.Read())
            {
                if (reader.Name == "attr" && reader.GetAttribute("n") == "id")
                    Id = Convert.ToInt32(reader.ReadInnerXml());
    
                if (reader.Name == "attr" && reader.GetAttribute("n") == "name")
                    Name = reader.ReadInnerXml();
    
                if (reader.Name == "attr" && reader.GetAttribute("n") == "street")
                    Address = new Address { Street = reader.ReadInnerXml() };
            }
        }
    
        public void WriteXml(XmlWriter writer)
        {
            //Start "struct"
            writer.WriteStartElement("struct");
            writer.WriteAttributeString("n", "People");
    
            writer.WriteStartElement("attr");
            writer.WriteAttributeString("n", "id");
            writer.WriteString(Id.ToString());
            writer.WriteEndElement();
    
            writer.WriteStartElement("attr");
            writer.WriteAttributeString("n", "name");
            writer.WriteString(Name.ToString());
            writer.WriteEndElement();
    
            //Start inner "struct"
            writer.WriteStartElement("struct");
            writer.WriteAttributeString("n", "Address");
    
            writer.WriteStartElement("attr");
            writer.WriteAttributeString("n", "street");
            writer.WriteString(Address.Street.ToString());
            writer.WriteEndElement();
    
            //End inner "struct"
            writer.WriteEndElement();
    
            //End "struct"
            writer.WriteEndElement();
        }
    }
    

    And you can serialize and deserialize your xml like.

    Person person = new Person
    {
        Id = 2,
        Name = "FIO FIO IFO",
        Address = new Address { Street = "Golden Gate" }
    };
    
    //--------------------Serialization----------------------------
    
    XmlSerializer serializer = new XmlSerializer(person.GetType());
    using (StreamWriter writer = new StreamWriter(@"Path to xml file"))
    {
        serializer.Serialize(writer, person);
    }
    
    //--------------------Deserialization----------------------------
    
    using (StringReader stringReader = new StringReader(File.ReadAllText(@"Path to same xml file that generated by above serializer")))
    {
        person = (Person)serializer.Deserialize(stringReader);
    
        Console.WriteLine("Id: " + person.Id);
        Console.WriteLine("Name: " + person.Name);
        Console.WriteLine("Street: " + person.Address.Street);
    
        Console.ReadLine();
    }
    

    Output for Serialization:

    enter image description here

    Output for Deserialization:

    enter image description here


    Alternative

    You can also create a custom methods to read and write xml.

    1) Write

    public static void WriteXml(Person person, string path)
    {
        using (XmlWriter writer = XmlWriter.Create(path))
        {
            //Start "struct"
            writer.WriteStartElement("struct");
            writer.WriteAttributeString("n", "People");
    
            writer.WriteStartElement("attr");
            writer.WriteAttributeString("n", "id");
            writer.WriteString(person.Id.ToString());
            writer.WriteEndElement();
    
            writer.WriteStartElement("attr");
            writer.WriteAttributeString("n", "name");
            writer.WriteString(person.Name.ToString());
            writer.WriteEndElement();
    
            //Start inner "struct"
            writer.WriteStartElement("struct");
            writer.WriteAttributeString("n", "Address");
    
            writer.WriteStartElement("attr");
            writer.WriteAttributeString("n", "street");
            writer.WriteString(person.Address.Street.ToString());
            writer.WriteEndElement();
    
            //End inner "struct"
            writer.WriteEndElement();
    
            //End "struct"
            writer.WriteEndElement();
        }
    }
    

    Usage:

    Person person = new Person
    {
        Id = 2,
        Name = "FIO FIO IFO",
        Address = new Address { Street = "Golden Gate" }
    };
    
    WriteXml(person, @"Path to xml file");
    

    2) Read

    public static Person ReadXml(string path)
    {
        Person person = new Person();
    
        using (XmlReader reader = XmlReader.Create(path))
        {
            while (reader.Read())
            {
                if (reader.Name == "attr" && reader.GetAttribute("n") == "id")
                    person.Id = Convert.ToInt32(reader.ReadInnerXml());
    
                if (reader.Name == "attr" && reader.GetAttribute("n") == "name")
                    person.Name = reader.ReadInnerXml();
    
                if (reader.Name == "attr" && reader.GetAttribute("n") == "street")
                    person.Address = new Address { Street = reader.ReadInnerXml() };
            }
        }
    
        return person;
    }
    

    Usage:

    Person result = ReadXml(@"Path to same xml file that generated by above serializer");