反序列化部分 JSON

Deserialize partial JSON

我正在尝试反序列化从旧 SignalR 服务收到的部分 JSON。

这是原文的例子JSON:

{
  "opt": {
    "data": {
      "DR": [{
          "O": [
            null,
            "18:46.401",
            "RGGW.GWWWR",
            "4.1",
            19,
            "17.852",
            "42.455",
            "",
            null,
            "+3.893",
            "277",
            "306",
            "",
            "310",
            "+0.058",
            null
          ],
          "OC": [
            "1"
          ]
        },
        {
          "O": [
            null,
            "1:41.119",
            "GYYG.WWWWW",
            "1.0",
            2,
            "17.561",
            "43.485",
            "40.073",
            null,
            "+16.772",
            "275",
            "291",
            "218",
            "291",
            "+16.772",
            null
          ],
          "OC": [
            "1"
          ]
        }
      ]
    }
  }
}

这是 JSON 收到的部分:

{
  "opt": {
    "data": {
      "DR": {
        "1": {
          "O": {
            "2": "WYYW.WWWWW",
            "7": "42.283",
            "12": "212"
          }
        }
      }
    }
  }
}

这些是我的 类:

    public class DR2
    {
        [JsonProperty("O")]
        public List<object> O { get; set; }
        [JsonProperty("OC")]
        public List<string> OC { get; set; }
    }

    public class Data4
    {
        [JsonProperty("DR")]
        public List<DR2> DR { get; set; }
    }

    public class Opt
    {
        [JsonProperty("data")]
        public Data4 data { get; set; }
    }

    public class SPFeed
    {
        [JsonProperty("opt")]
        public Opt opt { get; set; }
    }

尝试反序列化时收到经典错误:

JsonSerializationException: Cannot deserialize the current JSON object ... because the type requires a JSON array.

SPFeed partial_opt = JsonConvert.DeserializeObject<SPFeed>(test); // The error above

此外,尝试将 2 JSON 与下面的代码合并,没有合并,只有替换:

var object1 = JObject.Parse(JsonConvert.SerializeObject(spfeed));
var object2 = JObject.Parse(JsonConvert.SerializeObject(partial_opt));



object1.Merge(object2, new JsonMergeSettings
{
    MergeArrayHandling = MergeArrayHandling.Merge
});

我认为是因为部分 JSON 不是正确的数组。 还有其他反序列化方法吗?

这可能不是最干净的解决方案,但如果您可以检测 JSON 是否是部分的,那么您可以使用自定义合同解析器。这还需要对您的 class 结构进行一些更改。重新定义结构为

public interface IData{}
public class Data4Partial:IData
{
    [JsonProperty("DR")]
    public Dictionary<string,Dictionary<string,Dictionary<string,string>>> Data{get;set;}
}

public class DR2Full:IData
{
    [JsonProperty("O")]
    public List<object> O { get; set; } 
    [JsonProperty("OC")]
    public List<string> OC { get; set; }
}

public class Data4Full:IData
{
    [JsonProperty("DR")]
    public List<DR2Full> DR { get; set; }
}

public class Opt
{
    [JsonProperty("data")]
    public IData data { get; set; }
}

public class SPFeed
{
    [JsonProperty("opt")]
    public Opt opt { get; set; }
}

Contract Resolver 旨在替换 PropertyType,以便结果可以适应 Partial 和 Full Json。例如,

public class GenericContractResolver<T> : DefaultContractResolver  
{

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        var property = base.CreateProperty(member, memberSerialization);
        if (property.UnderlyingName == "data")
        {
            property.PropertyType = typeof(T);
        }
        return property;
    }
}

您现在可以将其用作

var partialResult = JsonConvert.DeserializeObject<SPFeed>(partialJson, new JsonSerializerSettings 
                                       { 
                                         ContractResolver = new GenericContractResolver<Data4Partial>() 
                                       }); 

var fullResult = JsonConvert.DeserializeObject<SPFeed>(fullJson
                                    , new JsonSerializerSettings 
                                       { 
                                         ContractResolver = new GenericContractResolver<Data4Full>() 
                                       });  

部分Json输出

完成Json输出

已解决:

var obj = JObject.Parse(partialJson);
Opt opt = root.SPFeed.opt;
if (obj["opt"]["data"]["DR"] != null) {
        IList<JToken> DR = JObject.Parse(obj["opt"]["data"]["DR"].ToString());
        var DRindex = Convert.ToInt32(((JProperty)DR[0]).Name);
        var O = ((JProperty)DR[0]).Value;

        JToken Otemp = JToken.Parse(O.ToString());

        if (Otemp["O"] != null)
        {
            var Oindex = Otemp["O"];
            foreach (JToken item in Oindex)
            {
                int index = Convert.ToInt32(((JProperty)item).Name);
                string value = ((JProperty)item).Value.ToString();
                Console.WriteLine("Index {0} Value {1}", index, value);
                opt.data.DR[DRindex].O[index] = value;
            }
        }
};