NewtonSoft JsonConvert - 反序列化JSON对象,看起来像{“@nil”:“真正的”}

NewtonSoft JsonConvert - 反序列化JSON对象,看起来像{“@nil”:“真正的”}

问题描述:

我试图反序列化由REST服务返回以下JSON:NewtonSoft JsonConvert - 反序列化JSON对象,看起来像{“@nil”:“真正的”}

[{ 
"Vehicle": { 
    "Id": "1", 
    "RenewalDate": { 
    "@nil": "true" 
    }  
}}] 

服务似乎翻译XML到JSON,因此XML nil作为JSON字符串的一部分包含在内。

请让我知道如何在Newtonsoft反序列化方法中处理这个问题?

如果更新日期包含在字符串中,反序列化工作正常。

+0

当原始XML中不是'nil'时,'''RenewalDate''的值是什么?你试图将JSON反序列化为什么样的c#模型?如果你只是做'JToken.Parse(jsonString)'它应该可以正常工作,所以请分享你的目标模型的反序列化失败。 – dbc

+0

这个[mcve]有没有机会?如果您向我们展示了迄今为止所做的工作以及确切的失败位置,我们更有可能为您提供可实际使用的解决方案。见[问]和https://codeblog.jonskeet.uk/2010/08/29/writing-the-perfect-question/。 – dbc

在没有你的问题的Minimal, Complete, and Verifiable example的,我会假设你正试图反序列化类的列表看起来像这样:

public class Vehicle 
{ 
    public string Id { get; set; } 

    [XmlElement(IsNullable = true)] 
    public DateTime? RenewalDate { get; set; } 
} 

public class RootObject 
{ 
    public Vehicle Vehicle { get; set; } 
} 

而且,反序列化失败的属性"RenewalDate",因为不存在JSON中出现的null值,因此存在包含翻译的xsi:nil="true"属性的对象。要解决这个

一种方式是引进以下custom JsonConverter

public class NullableStructConverter<T> : JsonConverter where T : struct 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return objectType == typeof(Nullable<T>); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     var underlyingType = Nullable.GetUnderlyingType(objectType); 
     if (underlyingType == null) 
      throw new InvalidOperationException(string.Format("Type {0} is not nullable", objectType)); 
     var token = JToken.Load(reader); 
     if (token.Type == JTokenType.Null) 
      return null; 
     if (token.WasNilXmlElement()) 
      return null; 
     return token.ToObject(underlyingType, serializer); 
    } 

    public override bool CanWrite { get { return false; } } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     throw new NotImplementedException(); 
    } 
} 

public static partial class JTokenExtensions 
{ 
    public static bool WasNilXmlElement(this JToken token) 
    { 
     if (token == null) 
      return true; 
     if (token.Type == JTokenType.Null) 
      return true; 
     var obj = token as JObject; 
     if (obj != null) 
     { 
      // Check if all properties were translated from XML attributes 
      // and one was translated from xsi:nil = true 
      // There might be namespaces present as well, e.g. 
      // "@xmlns:p3": "http://www.w3.org/2001/XMLSchema-instance" 
      if (obj.Properties().All(p => p.Name.StartsWith("@")) 
       && obj.Properties().Any(p => p.Name == "@nil" || p.Name.EndsWith(":nil") && p.Value.ToString() == "true")) 
       return true; 
     } 
     return false; 
    } 
} 

然后反序列化如下:

var settings = new JsonSerializerSettings 
{ 
    Converters = { new NullableStructConverter<DateTime>() } 
    // Whatever other settings you require. 
}; 
var root = JsonConvert.DeserializeObject<RootObject[]>(json, settings); 

工作.Net fiddle

另一种选择是将JSON装载到JToken层次结构,取代了从null JSON值nil XML元素翻译所有JSON对象,然后最后反序列化到模型。首先,介绍其使用WasNilXmlElement()从第一溶液中以下扩展方法:

public static partial class JTokenExtensions 
{ 
    public static JToken ReplaceNilXmlElementObjectsWithNull(this JToken root) 
    { 
     var rootContainer = root as JContainer; 
     if (rootContainer == null) 
      return root; 
     var list = rootContainer.DescendantsAndSelf() 
      .OfType<JObject>() 
      .Where(o => o.WasNilXmlElement()) 
      .ToList(); 
     foreach (var obj in list) 
     { 
      var replacement = JValue.CreateNull(); 
      if (obj.Parent != null) 
       obj.Replace(replacement); 
      if (root == obj) 
       root = replacement; 
     } 
     return root; 
    } 
} 

和反序列化如下:

var settings = new JsonSerializerSettings 
{ 
    // Whatever settings you require. 
}; 
var root = JsonConvert.DeserializeObject<JToken>(json, settings) 
    .ReplaceNilXmlElementObjectsWithNull() 
    .ToObject<RootObject[]>(JsonSerializer.CreateDefault(settings)); 

该溶液避免了对JsonConverter每个空类型的需要。工作fiddle #2