Ric
Ric

Reputation: 272

How to specify an XmlElement at a different level using XmlSerializer?

I have a class which I want to serialize to xml. I want to move one of the properties down a level in the generated xml (an element within an element) without changing the structure of the class. Is it possible to do this using XmlSerializer?

An example:

Generated xml:

<Person>
    <firstname xmlns=\"http://myschema.com\">John</firstname>
    <postcode xmlns=\"http://myschema.com\">N1 0XE</postcode>
</Person>

Desired xml:

<Person>
    <firstname xmlns=\"http://myschema.com\">John</firstname>
    <address>
        <postcode xmlns=\"http://myschema.com\">N1 0XE</postcode>
    </address>
</Person>

The code:

[Serializable]
[XmlType(Namespace = "http://myschema.com")]
public class Person
{
    [XmlElement("firstname")]
    public string FirstName { get; set; }

    [XmlElement("postcode")]
    public string Postcode { get; set; }
}

Serializer:

var xmlSerializer = new XmlSerializer(typeof(Person));
var stringWriter = new StringWriter();
var xmlWriter = XmlWriter.Create(stringWriter);

xmlSerializer.Serialize(xmlWriter, person);

Upvotes: 2

Views: 1913

Answers (2)

Anton Tykhyy
Anton Tykhyy

Reputation: 20076

There are two other ways out which require no changes whatsoever (not even implementing IXmlSerializable) to your class:

  1. a custom XmlWriter which will wrap <address> in an element as it is written;
  2. post-process XmlSerializer's output with a suitable XSL transform.

Upvotes: 1

Pilgerstorfer Franz
Pilgerstorfer Franz

Reputation: 8359

The only way I know to change the generated standard output xml is to implement IXmlSerializable. So you do not have to change the common structure but you do have to provide the implementation for some methods.

public class Person : IXmlSerializable
{
    [XmlElement("firstname")]
    public string FirstName { get; set; }

    [XmlElement("postcode")]
    public string Postcode { get; set; }

    #region IXmlSerializable Member

    public System.Xml.Schema.XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(System.Xml.XmlReader reader)
    {
        if (reader.Read())
        {
            FirstName = reader.ReadInnerXml();
        }

        reader.Read(); 

        Postcode = reader.ReadInnerXml();
    }

    public void WriteXml(System.Xml.XmlWriter writer)
    {
        writer.WriteElementString("firstname ", FirstName);
        writer.WriteStartElement("address");
        writer.WriteElementString("postcode", Postcode);
        writer.WriteEndElement();
    }

    #endregion

    // for demo purposes only !
    public override string ToString()
    {
        return FirstName + ", " + Postcode;
    }

    // source to test the exported file and read it right after!
    Person p = new Person() { FirstName = "jon doe", Postcode = "N1 OX" };

    XmlSerializer xs = new XmlSerializer(typeof(Person));
    StreamWriter sw = new StreamWriter("export.xml");
    xs.Serialize(sw, p);
    sw.Close();

    StreamReader sr = new StreamReader("export.xml");
    Person p1 = xs.Deserialize(sr) as Person;
    Debug.WriteLine(p1.ToString());

@XmlSubElement - there are only a bunch of attributes available for xmlSerialization. Unfortunatelly there is no subElement or anything comparable.

Upvotes: 3

Related Questions