2011-01-17 1 views
5

J'ai un document xml que je ne contrôle pas qui a un élément avec un type de données personnaliséDeserialize XML personnalisé type de données en C#

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

Je voudrais avoir une classe qui pourrait convertir automatiquement en quelques secondes Epoch:

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

     public EpochTime Time { get; set; } 
} 

Est-il possible de définir une classe EpochTime afin que le sérialiseur XML sait l'utiliser quand XML trouver avec type="epoch_time"? Et si oui, comment puis-je configurer les WriteXml et ReadXml pour le faire?

+0

('[Serializable]' ne fonctionne pas affecter la sérialisation xml) –

Répondre

4

La façon normale est de simplement shim avec une propriété qui se comporte comme prévu:

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 */ } 
    } 
} 

aussi, vous devez:

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

Voici un exemple complet avec votre 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; } 
} 
0

Avez-vous vraiment besoin de mettre en œuvre ISerializable? Ce qui suit pourrait fonctionner dans votre scénario:

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); 
    } 
} 

Notez également que [Serializable] n'a pas d'effet sur XmlSerializer.