Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deserialize custom XML datatype in C#

I have an xml document that I don't control that has an element with a custom datatype

<foo>
   <time type="epoch_seconds">1295027809.26896</time>
</foo>

I would like to have a class that could automatically convert to Epoch seconds:

[Serializable]
public class Foo
{
      public Foo()
      {
      }

      public EpochTime Time { get; set; }
}

Is there a way to define an EpochTime class so that the XML serializer knows to use it when finding XML with type="epoch_time"? And if so, how do I set up the WriteXml and ReadXml to do it?

like image 590
jimbojones Avatar asked Jan 17 '11 22:01

jimbojones


People also ask

What is XmlSerializer C#?

XML serialization is the process of converting an object's public properties and fields to a serial format (in this case, XML) for storage or transport. Deserialization re-creates the object in its original state from the XML output.

What is deserializing XML?

Deserialization is the process of reading an XML document and constructing an object that is strongly typed to the XML Schema (XSD) of the document. Before deserializing, an XmlSerializer must be constructed using the type of the object that is being deserialized.

Which annotation is needed for serialization and deserialization of XML format in the model classes?

Jackson annotations are useful in defining and controlling the process of serialization and deserialization across various formats such as XML, JSON, and YAML.


1 Answers

The normal way is to simply shim it with a property that behaves as you expect:

public class EpochTime {
    public enum TimeType {
       [XmlEnum("epoch_seconds")] Seconds
    }
    [XmlAttribute("type")] public TimeType Type {get;set;}
    [XmlText] public string Text {get;set;}

    [XmlIgnore] public DateTime Value {
        get { /* your parse here */ }
        set { /* your format here */ }
    }
}

also, you would need:

[XmlElement("time")]
public EpochTime Time { get; set; }

Here's a complete example with your xml:

using System;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
static class Program
{
    static void Main()
    {
        Foo foo;
        var ser = new XmlSerializer(typeof(Foo));
        using (var reader = XmlReader.Create(new StringReader(@"<foo>
   <time type=""epoch_seconds"">1295027809.26896</time>
</foo>")))
        {
            foo = (Foo)ser.Deserialize(reader);
        }
    }
}
public class EpochTime
{
    public enum TimeType
    {
        [XmlEnum("epoch_seconds")]
        Seconds
    }
    [XmlAttribute("type")]
    public TimeType Type { get; set; }
    [XmlText]
    public string Text { get; set; }
    private static readonly DateTime Epoch = new DateTime(1970, 1, 1);
    [XmlIgnore] public DateTime Value
    {
        get
        {
            switch (Type)
            {
                case TimeType.Seconds:
                    return Epoch + TimeSpan.FromSeconds(double.Parse(Text));
                default:
                    throw new NotSupportedException();
            }
        }
        set {
            switch (Type)
            {
                case TimeType.Seconds:
                    Text = (value - Epoch).TotalSeconds.ToString();
                    break;
                default:
                    throw new NotSupportedException();
            }
        }
    }
}
[XmlRoot("foo")]
public class Foo
{
    public Foo()
    {
    }

    [XmlElement("time")]
    public EpochTime Time { get; set; }
}
like image 83
Marc Gravell Avatar answered Oct 20 '22 00:10

Marc Gravell