XML反序列化处理具有默认值的空标签

Posted

技术标签:

【中文标题】XML反序列化处理具有默认值的空标签【英文标题】:XML Deserialization handle empty tags with Default values 【发布时间】:2021-05-26 16:35:14 【问题描述】:

我想在反序列化期间处理日期时间。如果 xml 没有节点或空值,那么我需要根据我设置的值将值设置为日期时间最小值或最大值的默认值。所以这里的问题是如果xml有startdate<startdate></startdate>这样的空值,那么我得到null而不是DateTime.MinValue。同样,我可能有一些其他节点,例如enddate,它需要 DateTime.MaxValue 作为默认值。如果我没有通过标签startdate,那么我会得到预期的 Minvalue。那么我如何处理空标签。如果标签为空,我也需要获取 Date Minvalue。

public static void Main()

    Program t = new Program();
        
        t.DeserializeObject("<OrderedItem><startdate>20210125</startdate><enddate>20210324</enddate></OrderedItem>");
        t.DeserializeObject("<OrderedItem></OrderedItem>");
        t.DeserializeObject("<OrderedItem><startdate></startdate><enddate></enddate></OrderedItem>"); //In this case i am getting issue, Output will not have default Min and Max Values


  private void DeserializeObject(string testData)
    
        // Create an instance of the XmlSerializer.
        XmlSerializer serializer =
        new XmlSerializer(typeof(OrderedItem));

        // Declare an object variable of the type to be deserialized.
        OrderedItem i;
        using (TextReader reader = new StringReader(testData))
        
            i = (OrderedItem)serializer.Deserialize(reader);
        
    Console.Write("Start date is "+i.Startdate.Date+"\n");
    Console.Write("End date is "+i.Enddate.Date+"\n\n");
    
    

public class OrderedItem

    
    [XmlElement(ElementName = "startdate")]
    [DefaultValue(typeof(DateTime), "0001-01-01T00:00:00")]
 public CustomDateTime Startdate  
        get; 
        set;
     = new CustomDateTime  Date = DateTime.MinValue ;

 [XmlElement(ElementName = "enddate")]
    [DefaultValue(typeof(DateTime), "9999-12-31T00:00:00")]
 public CustomDateTime Enddate  
        get; 
        set;
     = new CustomDateTime  Date = DateTime.MaxValue ;

在我的 CustomDateTime 中,我使用的是 IXmlSerializable,下面是部分代码

public class CustomDateTime : IXmlSerializable, IComparable, IComparable<DateTime>

    static string[] formats = new string[]  "yyyyMMdd", "yyyy-MM-dd" ;
    [XmlIgnore]
    public DateTime? Date
    
        get;
        set;
    
   // here i have CompareTo and other methods which implements interface
public void ReadXml(XmlReader reader)
    
        string input = reader.ReadString();

        DateTime inputDate;
        if (DateTime.TryParseExact(input, formats, CultureInfo.InvariantCulture, DateTimeStyles.None, out inputDate))
        
            Date = inputDate;
        
        else
        
            Date = null;
        
        reader.ReadEndElement();
    

    public void WriteXml(XmlWriter writer)
    
        if (Date != null)
        
            writer.WriteString(Date.Value.ToString("yyyyMMdd"));
        
    

实际输出

开始日期是 1/25/2021 12:00:00 AM 结束日期是 3/24/2021 12:00:00 AM

开始日期是 1/1/0001 12:00:00 AM 结束日期是 12/31/9999 晚上 11:59:59

开始日期是 结束日期是

预期输出

开始日期是 1/25/2021 12:00:00 AM 结束日期是 3/24/2021 12:00:00 AM

开始日期是 1/1/0001 12:00:00 AM 结束日期是 12/31/9999 晚上 11:59:59

开始日期是 1/1/0001 12:00:00 AM 结束日期是 12/31/9999 晚上 11:59:59

小提琴:https://dotnetfiddle.net/qv7sjP

我想我可以根据需要将[DefaultValue(typeof(DateTime), "0001-01-01T00:00:00")][DefaultValue(typeof(DateTime), "9999-12-31T00:00:00")] 之类的默认值属性添加到属性StartdateEnddate 并在ReadXml 方法中读取它,然后在标签不存在时在ReadXml 方法中设置Date 属性(否则阻止)。我不确定如何阅读和处理它。我也不确定这是不是合适的解决方案

【问题讨论】:

【参考方案1】:

尝试以下:

    public class OrderedItem
    
        private DateTime _Startdate = new DateTime();
        [XmlElement(ElementName = "startdate")]
        public DateTime Startdate  
            get return _Startdate; 
            set _Startdate = value;
        

        private DateTime _Enddate = new DateTime();
        [XmlElement(ElementName = "enddate")]
        public DateTime Enddate
        
            get  return _Enddate; 
            set  _Enddate = value; 
        
    

【讨论】:

我使用的是 CustomDate 类而不是 Datetime。但是根据您的建议,我使用 CustomDate 修改了我的代码,它不会解决原始问题。请参阅小提琴以获取参考 dotnetfiddle.net/K5Z9gR 。我根据您提供的建议创建了这个,如果我做错了什么请告诉我 我会在 CustomDateTime 中创建默认构造函数 new DateTime : public CustomDateTime() Date = new DateTime(); 好的。但我不希望当前日期时间成为默认值。我想要基于我的属性的 DateTime 最小值或最大值。我也指定了它们。在有问题的共享代码中,我采用了 3 个示例 XML 输入。我在第三种情况下面临问题 new DataTime() 是 1/1/01。 public CustomDateTime(DateTime date) Date = date; 好的。如果我这样做。开始日期和结束日期都将具有相同的默认日期 01 年 1 月 1 日。但我想设置不同的默认值(在问题中提到,我正在尝试最小值和最大值)。当 XML 具有空值节点时,也会发生我的问题。所以这是在构造函数中设置值之后发生的。因此,在我的情况下,该值将被空覆盖。从有问题的小提琴共享中,我能够重现该问题。我觉得您没有理解我在问题中提到的原始问题。如果我遗漏了什么或者我需要适当地重写问题,请告诉我。

以上是关于XML反序列化处理具有默认值的空标签的主要内容,如果未能解决你的问题,请参考以下文章

如何将所有字段都是默认值的类型反序列化为 None ?

Xml 序列化与“真”和“假”

如何反序列化java Long哪个xml标签有xsi:nil?

为啥 Azure WebJob ServiceBus 默认反序列化 XML?

C#中具有复杂元素的Xml反序列化[重复]

ProtoBuf简介