Chris Kessell
Chris Kessell

Reputation: 71

Using C# XML Serializer to produce custom XML format

I'm using Visual Studio 2013 and trying to use the C# XML serializer/deserializer to convert variables stored in a class to/from an XML file (something I'm a novice at).

Given a simple class:

public class TestXML
{
    public String Label = "Hello";
    public Boolean Enable = true;
    public Int32 PosX = 12;
    public Int32 PosY = 34;
}

by default the serializer produces XML in the form:

<TestXML>
  <Label>Hello</Label>
  <Enable>true</Enable>
  <PosX>12</PosX>
  <PosY>34</PosY>
</TestXML>

Unfortunately, however, my project requirements state that the parameters in the XML file must be formatted as:

<TestXML>
  <model>
    <prop name="Label" value="Hello" />
    <prop name="Enable" value="true" />
    <prop name="PosX" value="12" />
    <prop name="PosY" value="34" />
  </model>
</TestXML>

I've been looking at using the XmlAttribute and XmlElement options to control the XML formatting but can't see any way to produce the required format. Is there any way to make the serializer store variables in this specific format?

Upvotes: 3

Views: 4101

Answers (4)

dario
dario

Reputation: 5259

You can't do that using XmlAttributeAttribute. You better implement the IXmlSerializable interface.

public class TestXML : IXmlSerializable
{
    public String Label = "Hello";
    public Boolean Enable = true;
    public Int32 PosX = 12;
    public Int32 PosY = 34;

    public void WriteXml(XmlWriter writer)
    {
        // Serialize
    }

    public void ReadXml(XmlReader reader)
    {
        // Deserialize
    }

    public XmlSchema GetSchema()
    {
        return null;
    }
}

In this way you have full control on the shape of your XML. You can find all the information you need to serialize/deserialize your class here.

Upvotes: 2

Yoh Deadfall
Yoh Deadfall

Reputation: 2781

This can be done only by implementing the IXmlSerializable interface which allows you to customize shaping of your XML.

public class TestXML : IXmlSerializable
{
    public String Label = "Hello";
    public Boolean Enable = true;
    public Int32 PosX = 12;
    public Int32 PosY = 34;

    XmlSchema IXmlSerializable.GetSchema()
    {
        return null;
    }

    void IXmlSerializable.ReadXml(XmlReader reader)
    {
        reader.ReadStartElement();
        reader.ReadStartElement("model");

        if (reader.Name != "prop")
        { throw new InvalidOperationException(); }

        do
        {
            if (!reader.MoveToAttribute("name"))
            { throw new InvalidOperationException(); }

            string name = reader.Value;

            if (!reader.MoveToAttribute("value"))
            { throw new InvalidOperationException(); }

            switch (name)
            {
                case "Label": Label = reader.Value; break;
                case "Enable": Enable = XmlConvert.ToBoolean(reader.Value); break;
                case "PosX": PosX = XmlConvert.ToInt32(reader.Value); break;
                case "PosY": PosY = XmlConvert.ToInt32(reader.Value); break;
            }
        }
        while (reader.ReadToNextSibling("prop"));

        reader.ReadEndElement();
        reader.ReadEndElement();
    }

    void IXmlSerializable.WriteXml(XmlWriter writer)
    {
        writer.WriteStartElement("model");
        WriteProperty(writer, "Label", Label);
        WriteProperty(writer, "Enable", XmlConvert.ToString(Enable));
        WriteProperty(writer, "PosX", XmlConvert.ToString(PosX));
        WriteProperty(writer, "PosY", XmlConvert.ToString(PosY));
        writer.WriteEndElement();
    }

    private void WriteProperty(XmlWriter writer, string name, string value)
    {
        writer.WriteStartElement("prop");
        writer.WriteAttributeString("name", name);
        writer.WriteAttributeString("value", value);
        writer.WriteEndElement();
    }
}

Links:

  1. IXmlSerializable Interface
  2. How to Implement IXmlSerializable Correctly

Upvotes: 1

Wigle
Wigle

Reputation: 106

You can create three classes,

public class TextXML
{
 public Model model {get; set;}
}
public class Model
{      
 public List<prop> props{get; set;}
}
public class prop
{
public string name{get; set;}
public string value{get; set;}

}

and use XmlAttributes to serialize it. use XmlArray for the prop class in your model class.

If you have any further questions don`t be shy, I am currently working on a project that uses a lot of xml and the attributes.

Upvotes: 0

Charles Mager
Charles Mager

Reputation: 26213

Manually controlling serialization per king.code's answer is one option (so I won't repeat it). The other option is to structure your model differently or, if not an option, to create another 'data model' and map your existing model to this and serialize that instead. This may be easier than lots of low-level XmlReader / XmlWriter code.

To get the result you're after, you'd need something like this:

public class TestXml
{
    [XmlArray("model")]
    [XmlArrayItem("prop")]
    public List<Prop> Props { get; set; }
}


public class Prop
{
    [XmlAttribute("name")]
    public string Name { get; set; }

    [XmlAttribute("value")]
    public string Value { get; set; }
}

This content:

var xml = new TestXml
{
    Props = new List<Prop>
    {
        new Prop
        {
            Name = "Label",
            Value = "Hello"
        }
    }
};

Would then serialize to this:

<TestXML>
  <model>
    <prop name="Label" value="Hello" />
  </model>
</TestXML>

Upvotes: 4

Related Questions