简体   繁体   English

在C#中反序列化自定义XML数据类型

[英]Deserialize custom XML datatype in C#

I have an xml document that I don't control that has an element with a custom datatype 我有一个我无法控制的xml文档,它有一个带有自定义数据类型的元素

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

I would like to have a class that could automatically convert to Epoch seconds: 我想有一个类可以自动转换为Epoch秒:

[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" ? 有没有办法定义EpochTime类,以便XML序列化器在查找type="epoch_time" XML时知道使用它? And if so, how do I set up the WriteXml and ReadXml to do it? 如果是这样,我如何设置WriteXmlReadXml来做到这一点?

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: 这是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; }
}

Do you really need to implement ISerializable ? 你真的需要实现ISerializable吗? The following might work in your scenario: 以下可能适用于您的方案:

public class EpochTime
{
    [XmlText]
    public double Data { get; set; }
    [XmlAttribute("type")]
    public string Type { get; set; }
}

public class Foo
{
    public EpochTime Time { get; set; }
}

class Program
{
    public static void Main()
    {
        var foo = new Foo
        {
            Time = new EpochTime
            {
                Data = 1295027809.26896,
                Type = "epoch_seconds"
            }
        };
        var serializer = new XmlSerializer(foo.GetType());
        serializer.Serialize(Console.Out, foo);
    }
}

Also notice that [Serializable] has no effect on XmlSerializer . 另请注意, [Serializable]XmlSerializer没有影响。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM