无法修改XSD时,如何重写XmlSerializer的DateTime序列化格式?
问题描述
我有一个定义了如下DateTime类型的XSD:
<xs:simpleType name="ISODateTime"> <xs:restriction base="xs:dateTime"/> </xs:simpleType>
使用xsd.exe生成对应类后,该类型的元素会被生成为DateTime属性:
public System.DateTime dtName { get { return this.dtNameField; } set { this.dtNameField = value; } }
序列化该类实例时,XmlSerializer会将DateTime转换为2023-04-28T14:47:37.0001+02:00格式,但我需要将其格式化为YYYY-MM-DDThh:mm:ss.sssZ或YYYY-MM-DDThh:mm:ss.sss+/-hh:mm格式。我无法修改XSD及XML验证规则,请问是否有办法重写XmlSerializer的DateTime序列化格式?
解决方案
可以通过以下两种方式实现DateTime序列化格式的自定义:
方法一:用XmlAttributeOverrides替换序列化逻辑
通过XmlAttributeOverrides为目标DateTime属性指定自定义序列化处理类,无需修改生成的代码:
// 自定义DateTime序列化处理类 public class CustomDateTimeSerializer : IXmlSerializable { private DateTime? _dateValue; public CustomDateTimeSerializer() { } public CustomDateTimeSerializer(DateTime value) => _dateValue = value; public XmlSchema GetSchema() => null; public void ReadXml(XmlReader reader) { if (DateTime.TryParse(reader.ReadElementContentAsString(), out var parsedDate)) { _dateValue = parsedDate; } } public void WriteXml(XmlWriter writer) { if (_dateValue.HasValue) { // 按需求输出对应格式 string formattedDate = _dateValue.Value.Kind switch { DateTimeKind.Utc => _dateValue.Value.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"), DateTimeKind.Local => _dateValue.Value.ToString("yyyy-MM-ddTHH:mm:ss.fffzzz"), _ => _dateValue.Value.ToString("yyyy-MM-ddTHH:mm:ss.fff") }; writer.WriteString(formattedDate); } } // 隐式转换,方便和DateTime类型互转 public static implicit operator DateTime(CustomDateTimeSerializer serializer) => serializer._dateValue ?? DateTime.MinValue; public static implicit operator CustomDateTimeSerializer(DateTime dateTime) => new CustomDateTimeSerializer(dateTime); } // 创建自定义XmlSerializer实例 var overrides = new XmlAttributeOverrides(); var xmlAttrs = new XmlAttributes(); xmlAttrs.XmlElements.Add(new XmlElementAttribute { ElementName = "dtName", Type = typeof(CustomDateTimeSerializer) }); overrides.Add(typeof(YourGeneratedClass), "dtName", xmlAttrs); var customSerializer = new XmlSerializer(typeof(YourGeneratedClass), overrides); // 序列化示例 using var stringWriter = new StringWriter(); customSerializer.Serialize(stringWriter, yourClassInstance); string resultXml = stringWriter.ToString();
方法二:修改生成类,新增代理属性
虽然不能改XSD,但可以修改xsd.exe生成的类(后续重新生成时需注意保留修改,或通过脚本自动化修改):
// 原DateTime属性添加XmlIgnore标记,让XmlSerializer忽略它 [XmlIgnore] public System.DateTime dtName { get { return this.dtNameField; } set { this.dtNameField = value; } } // 新增对应XML元素的字符串属性,处理自定义格式 [XmlElement("dtName")] public string dtNameXml { get { return dtName.Kind switch { DateTimeKind.Utc => dtName.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"), DateTimeKind.Local => dtName.ToString("yyyy-MM-ddTHH:mm:ss.fffzzz"), _ => dtName.ToString("yyyy-MM-ddTHH:mm:ss.fff") }; } set { // 反序列化时转换回DateTime类型 if (DateTime.TryParse(value, out var parsedDate)) { dtName = parsedDate; } } }
注意事项
- 两种方案都要保证生成的XML符合
xs:dateTime的验证规则,避免XML校验失败。 - 方法一无需修改生成类,但序列化时必须使用自定义的XmlSerializer实例;方法二更直观,但需要维护生成类的修改。
内容的提问来源于stack exchange,提问作者musium
相关产品推荐
相关产品推荐

