在XML反序列化中将空字符串处理为空

在XML反序列化中将空字符串处理为空

问题描述:

对于this question,我有同样的问题。我使用基于SOAP的API来回发送数据,其中响应不符合标准,特别是空值。对于DateTime,该API将发送回一个空字符串,像这样:在XML反序列化中将空字符串处理为空

<nextreview></nextreview> 

导致反序列化上出现以下错误:

字符串“”不是一个有效的AllXsd值。

所以我的想法是创建一个自定义空类型,NullableOrEmpty<T>,通过转换为null实施IXMLSerializable,处理空字符串。问题是我只想处理空字符串的例外情况。我想用正常的序列化和反序列化来使用'默认'行为。我如何在下面的代码中模拟序列化的默认行为?

public class NullableOrEmpty<T> : IXmlSerializable 
    where T : struct 
{ 
    public T? NullableValue { get; set; } 
    public T Value { get { return this.NullableValue.Value; } } 
    public bool HasValue { get { return this.NullableValue.HasValue; } } 

    ... 

    public void ReadXml(XmlReader reader) 
    { 
     string xml = reader.ReadElementContentAsString(); 
     if (string.IsNullOrEmpty(xml)) 
     { 
      this.NullableValue = null; 
     } 
     else 
     { 
      //THIS SHOULD DO THE DEFAULT. THIS DOESN'T WORK. WHAT DO I DO?? 
      //this.NullableValue = (T?)new XmlSerializer(typeof(T?)).Deserialize(reader); 
     } 
    } 

    public void WriteXml(XmlWriter writer) 
    { 
     //THIS SHOULD DO THE DEFAULT. THIS DOESN'T WORK. WHAT DO I DO?? 
     //new XmlSerializer(typeof(T?)).Serialize(writer, this.NullableValue); 
    } 

} 

当我说“这行不通”,它专门生成以下错误消息,可能是因为它试图消耗的东西,是不是有:

有一个错误XML文档(63, 6)。

<lastreview xmlns=''>不是 预计。

这是在该位置的XML片段。该错误是由价值birthdate造成的,因为我不是在价值实际上是赋予非特殊情况下正确地消费它:

<udf4></udf4> 
<udf3></udf3> 
<birthdate>1978-05-24Z</birthdate> 
<lastreview></lastreview> 
<fulltime>1</fulltime> 

任何想法或想法赞赏。如果需要,我可以发布更多代码示例或测试出建议。谢谢!

+1

你不能使用相同的'XmlReader'。您已经阅读过要再次阅读的内容。 – 2011-05-24 22:01:15

你可以在这里做的一件事,尽管它可能更多的痛苦是实现适配器模式,其中从xml结果填充的对象只具有字符串类型的属性,然后编写一个转换器方法来填充当目标属性是DateTime时,'真实'对象检查空字符串。这可能比实现自己的序列化器更容易。

+0

感谢您的想法。我想避免添加一堆逻辑,因为它只影响100个属性中的5个。我已经在这里看到了shim属性的概念:http://stackoverflow.com/questions/838246/xml-deserialization-of-a-date-with-an-empty-value,这是我最终可能使用的。 – mellamokb 2011-05-25 14:41:45

+0

您的链接看起来像是一个非常好的解决方案。易于阅读,易于维护。 – Jay 2011-05-25 14:55:07

我不再使用这个类(我需要通过,而不是第三方验证),但我实际上是能够通过使用XmlConvert助手手工处理所有的数据类型得到它的工作:

public void ReadXml(XmlReader reader) 
{ 
    string xml = reader.ReadElementContentAsString(); 
    if (string.IsNullOrEmpty(xml)) 
    { 
     this.NullableValue = null; 
    } 
    else 
    { 
     if (this.NullableValue is bool) 
      this.NullableValue = (T?)Convert.ChangeType(XmlConvert.ToBoolean(xml), typeof(T?)); 
     else if (this.NullableValue is byte) 
      this.NullableValue = (T?)Convert.ChangeType(XmlConvert.ToByte(xml), typeof(T?)); 
     else if (this.NullableValue is char) 
      this.NullableValue = (T?)Convert.ChangeType(XmlConvert.ToChar(xml), typeof(T?)); 
     else if (this.NullableValue is DateTime) 
      this.NullableValue = (T?)Convert.ChangeType(XmlConvert.ToDateTime(xml), typeof(T?)); 
     else if (this.NullableValue is decimal) 
      this.NullableValue = (T?)Convert.ChangeType(XmlConvert.ToDecimal(xml), typeof(T?)); 
     else if (this.NullableValue is double) 
      this.NullableValue = (T?)Convert.ChangeType(XmlConvert.ToDouble(xml), typeof(T?)); 
     else if (this.NullableValue is Guid) 
      this.NullableValue = (T?)Convert.ChangeType(XmlConvert.ToGuid(xml), typeof(T?)); 
     else if (this.NullableValue is short) 
      this.NullableValue = (T?)Convert.ChangeType(XmlConvert.ToInt16(xml), typeof(T?)); 
     else if (this.NullableValue is int) 
      this.NullableValue = (T?)Convert.ChangeType(XmlConvert.ToInt32(xml), typeof(T?)); 
     else if (this.NullableValue is long) 
      this.NullableValue = (T?)Convert.ChangeType(XmlConvert.ToInt64(xml), typeof(T?)); 
     else if (this.NullableValue is float) 
      this.NullableValue = (T?)Convert.ChangeType(XmlConvert.ToSingle(xml), typeof(T?)); 
    } 
} 

public void WriteXml(XmlWriter writer) 
{ 
    new XmlSerializer(typeof(T?)).Serialize(writer, this.NullableValue); 
}