重写XmlSerializer中的日期时间分析,而不更改生成的代码

本文关键字:代码 XmlSerializer 日期 时间 重写 | 更新日期: 2023-09-27 18:21:41

我正在访问第三方API并检索一些XML。我还能够访问它的xsd,并使用xsd生成对象以使用XmlSerializer进行反序列化。

XML包含这样的日期:

<modified>2014-08-19T06:39:13.269-0400</modified>

生成的代码如下所示:

    [System.Xml.Serialization.XmlElementAttribute(DataType="time")]
    public System.DateTime modified {
        get {
            return this.modifiedField;
        }
        set {
            this.modifiedField = value;
        }
    }

不幸的是,这会在尝试反序列化时导致错误。

我可以通过用XmlIgnore属性标记它并将这样的代码添加到分部类中来解决这个问题:

    [XmlElement("modified")]
    public string modifiedAsString
    {
        get { return this.modified.ToString(); }
        set { this.modified = System.DateTime.Parse(value); }
    }

然而,忽略部分是对生成的类的更改,我必须进行数百次这样的更改才能考虑到所有的日期时间。

我尝试了MetadataType这件事来从外部将属性应用到它,但不幸的是XmlSerializer没有接受。

有人建议我如何在不更改生成的代码或输入XML(这超出了我的控制范围)的情况下解析它吗?

重写XmlSerializer中的日期时间分析,而不更改生成的代码

如果您愿意将System.DateTime更改为具有到System.DateTime的隐式运算符的自定义包装类,则这是可能的。尽管我怀疑这可能比被忽略的helper属性更具破坏性。

您可以创建一个自定义类型来包装底层DateTime,并执行必要的to/from解析。此外,您可以利用XmlTextAttribute来控制输出以匹配<modified>2014-08-19T06:39:13.269-0400</modified>模式:

public struct CustomDateTime
{
    private DateTime UnderlyingDateTime;
    [XmlText]
    public string CustomFormat
    {
        get { return UnderlyingDateTime.ToString(); }
        set { UnderlyingDateTime = System.DateTime.Parse(value); }
    }
    public static implicit operator DateTime(CustomDateTime custom)
    {
        return custom.UnderlyingDateTime;
    }
    public static implicit operator CustomDateTime(DateTime datetime)
    {
        return new CustomDateTime { UnderlyingDateTime = datetime };
    }
}

这是一个包含Modified属性的类(您没有提到名称,所以我只将其称为Foo):

public class Foo
{
    public CustomDateTime Modified { get; set; }
}

隐式运算符允许您在大多数情况下直接读取/写入DateTime值:

Foo f = new Foo();
f.Modified = DateTime.Parse("2014-08-19T06:39:13.269-0400");

它支持您的标准火炬XmlSerializer系列化:

XmlSerializer serializer = new XmlSerializer(typeof(Foo));
var textwriter = new StringWriter();
serializer.Serialize(textwriter, f);
string xml = textwriter.ToString();
Console.WriteLine(xml);

得到的XML(我已经去掉了一些通常会在根节点中的包装垃圾)是:

<Foo>
  <Modified>2014-08-19 6:39:13 AM</Modified>
</Foo>

反序列化上面的XML:

Foo deserialized = (Foo)serializer.Deserialize(new StringReader(xml));
DateTime datetime = deserialized.Modified;
Console.WriteLine(datetime);

DateTime输出的结果:2014-08-19 6:39:13 AM

现在,这与XML内容并不完全匹配,也就是说,它显示的是"2014-08-19 6:39:13 AM",而不是"2014-08-19T06:39:13.269-0400",但这只是因为我逐字逐句地跟踪您对get/set属性使用DateTime.ToString()DateTime.Parse的情况

然而,它会很好地读取XML内容,也就是说,如果传入的XML是:

<Foo>
  <Modified>2014-08-19T06:39:13.269-0400</Modified>
</Foo>

它仍然以相同的方式读取它(本质上它将调用System.DateTime.Parse("2014-08-19T06:39:13.269-0400"))。

编辑:只是澄清一下,你必须做出的突破性改变是将你原来的Foo类从这个改为:

public class Foo
{
    public DateTime Modified { get; set; }
}

对此:

public class Foo
{
    public CustomDateTime Modified { get; set; }
}

我不确定在这种用法中是否正确模拟了[System.Xml.Serialization.XmlElementAttribute(DataType="time")]属性的行为,但如果没有,您很容易就必须灵活地在CustomDateTime.CustomFormat属性getter和setter中实现任何解析。