反序列化部分 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;
}
}
};
我正在尝试反序列化从旧 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;
}
}
};