2011-05-24 167 views
0

對於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

回答

2

你可以在這裏做的一件事,儘管它可能更多的痛苦是實現適配器模式,其中從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

0

我不再使用這個類(我需要通過,而不是第三方驗證),但我實際上是能夠通過使用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); 
}