custom Xml Serializer to make value as an xml element

509 Views Asked by At

Classes:

public class Employee
{
    public int Id { get; set; }

    public PhoneNumber[] Numbers { get; set; }
}

public class PhoneNumber
{
    public string Type { get; set; }

    public string Number { get; set; }
}

Code to serialize:

var xmlSerializer = new XmlSerializer(typeof(Employee));

var xwSettings = new XmlWriterSettings {Indent = true, OmitXmlDeclaration = true};

string serializedResult;
using (var stream = new StringWriter())
using (var writer = XmlWriter.Create(stream, xwSettings))
{
    xmlSerializer.Serialize(writer, emp);
    serializedResult = stream.ToString();
}

Current Result:

<Employee>
  <Id>1</Id>
  <Numbers>
    <PhoneNumber>
      <Type>Home</Type>
      <Number>1231231231</Number>
    </PhoneNumber>
    <PhoneNumber>
      <Type>Office</Type>
      <Number>3453453453</Number>
    </PhoneNumber>
  </Numbers>
</Employee>

Desired Result:

<Employee>
  <Id>1</Id>
  <Numbers>
    <Home>1231231231</Home>
    <Office>3453453453</Office>
  </Numbers>
</Employee>

PhoneNumber Type can be added dynamically like "GuestRoomPhone" etc, so adding properties for each phone number type is not an option.

1

There are 1 best solutions below

0
gunnerone On BEST ANSWER

You can do this by implementing the IXmlSerializable interface on your classes. This allows you to control how the values are written and read.

public class Employee : IXmlSerializable
{
    public int Id { get; set; }

    public PhoneNumber[] Numbers { get; set; }

    public XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(XmlReader reader)
    {
        reader.ReadStartElement("Employee");
        reader.ReadStartElement("Id");
        Id = reader.ReadContentAsInt();
        reader.ReadEndElement();    // Id

        reader.ReadStartElement("Numbers");

        List<PhoneNumber> numbers = new List<PhoneNumber>();
        while (reader.MoveToContent() == XmlNodeType.Element)
        {
            PhoneNumber num = new PhoneNumber();
            num.ReadXml(reader);
            numbers.Add(num);
        }
        Numbers = numbers.ToArray();

        reader.ReadEndElement();    // Numbers
        reader.ReadEndElement();    // Employee
    }

    public void WriteXml(XmlWriter writer)
    {
        writer.WriteStartElement("Id");
        writer.WriteValue(Id);
        writer.WriteEndElement();

        writer.WriteStartElement("Numbers");

        foreach (PhoneNumber num in Numbers)
        {
            num.WriteXml(writer);
        }

        writer.WriteEndElement();   // Numbers
    }
}

Similarly for the PhoneNumber class.

public class PhoneNumber : IXmlSerializable
{
    public string Type { get; set; }
    public string Number { get; set; }

    public XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(XmlReader reader)
    {
        while (!reader.IsStartElement())
            reader.Read();
        Type = reader.Name;
        Number = reader.ReadElementContentAsString();
    }

    public void WriteXml(XmlWriter writer)
    {
        writer.WriteStartElement(Type);
        writer.WriteString(Number);
        writer.WriteEndElement();
    }
}