JSON数据未转换为列表 [英] Json data not converting to List
问题描述
我有一个未正确序列化的json数据. 我已经附上了预期的和不好的一个.
I have a json data which was not serialized properly. I have attached the expected and bad one.
我需要处理错误的json,并以正确的格式获取
I need to handle the bad json, get in a right format
预期
"channels": {
"heart-rate": {
"events": {
"type": "Project.Model.ChannelEvents.HeartRateChannelEvent, Project, Version=1.2.7.0, Culture=neutral, PublicKeyToken=null",
"structure": [
"beatsPerMinute",
"offset"
],
"list": [
[
40,
0
]
]
}
},
"location": {
"events": {
"type": "Project.Model.ChannelEvents.LocationChannelEvent, Project, Version=1.2.7.0, Culture=neutral, PublicKeyToken=null",
"structure": [
"latitude",
"longitude",
"offset"
],
"list": [
[
0.0,
0.0,
0
]
]
}
}
}
badjson 这是需要在控制台应用程序中格式化的错误json数据
badjson This is the bad json data which needs to be formatted, in a console application
"channels": {
"heart-rate": {
"events": {
"$type": "System.Collections.Generic.List`1[[Project.Model.Activity+Channel+Event, Project]], mscorlib",
"$values": [{
"$type": "Project.Model.ChannelEvents.HeartRateChannelEvent, Project",
"beatsPerMinute": 40,
"offset": 0
}
]
}
},
"location": {
"events": {
"$type": "System.Collections.Generic.List`1[[Project.Model.Activity+Channel+Event, Project]], mscorlib",
"$values": [{
"$type": "Project.Model.ChannelEvents.LocationChannelEvent, Project",
"latitude": 0.0,
"longitude": 0.0,
"offset": 0
}
]
}
}
}
推荐答案
首先,您的输入和输出JSON在语法上均无效:它们缺少大括号{
和}
.对于此答案的其余部分,我将假定这是问题中的错字.
Firstly, both your input and output JSON are syntactically invalid: they are missing outer braces {
and }
. For the remainder of this answer, I'm going to assume this is a typo in the question.
假设您尚未安装,请安装此处所示,然后使用
Assuming you have not done so already, you could install json.net as shown here and then use LINQ to JSON to load and modify your JSON. Using this approach avoids the need to define c# types that perfectly match your JSON.
您输入的JSON有两个问题:
Your input JSON has two problems:
-
标记
"channels.heart-rate.events"
和"channels.location.events"
是对象的数组,其属性的存在可以明显看出,JSON最初是使用Json.NET生成的)
The tokens
"channels.heart-rate.events"
and"channels.location.events"
are arrays of objects for which Json.NET type information has been included. (It is clear from the presence of the"$type"
property that the JSON was originally generated using Json.NET)
您想要的是将这些数组重新格式化为一个包含项目类型,项目属性名称数组和项目属性值数组的对象.
What you want instead is for these arrays to be reformatted into a single object that contains the item type, an array of item property names, and an array of array of item property values.
类型信息已使用 TypeNameAssemblyFormat = FormatterAssemblyStyle.Simple
一个>.您要添加程序集信息,将其转换为 FormatterAssemblyStyle.Full
格式.
The type information has been formatted using TypeNameAssemblyFormat = FormatterAssemblyStyle.Simple
. You want to add assembly information, converting to FormatterAssemblyStyle.Full
format.
这两个都可以使用LINQ-to-JSON进行纠正.假设您有两个流,分别是Stream inputStream
和Stream outputStream
流,该流与要修复的JSON流和用于存储修复的JSON的流相对应.然后,介绍以下实用程序方法:
Both of these can be corrected using LINQ-to-JSON. Say you have two streams, Stream inputStream
and Stream outputStream
corresponding to a stream with the JSON to be fixed and a stream in which to store the fixed JSON. Then, introduce the following utility methods:
public static class JsonExtensions
{
const string JsonTypeName = @"$type";
const string JsonValuesName = @"$values";
public static void ReformatCollections(Stream inputStream, Stream outputStream, IEnumerable<string> paths, Func<string, string> typeNameMapper, Formatting formatting)
{
var root = JToken.Load(new JsonTextReader(new StreamReader(inputStream)) { DateParseHandling = DateParseHandling.None });
root = ReformatCollections(root, paths, typeNameMapper);
var writer = new StreamWriter(outputStream);
var jsonWriter = new JsonTextWriter(writer) { Formatting = formatting };
root.WriteTo(jsonWriter);
jsonWriter.Flush();
writer.Flush();
}
public static JToken ReformatCollections(JToken root, IEnumerable<string> paths, Func<string, string> typeNameMapper)
{
foreach (var path in paths)
{
var token = root.SelectToken(path);
var newToken = token.ReformatCollection(typeNameMapper);
if (root == token)
root = newToken;
}
return root;
}
public static JToken ReformatCollection(this JToken value, Func<string, string> typeNameMapper)
{
if (value == null || value.Type == JTokenType.Null)
return value;
var array = value as JArray;
if (array == null)
array = value[JsonValuesName] as JArray;
if (array == null)
return value;
// Extract the item $type and ordered set of properties.
string type = null;
var properties = new Dictionary<string, int>();
foreach (var item in array)
{
if (item.Type == JTokenType.Null)
continue;
var obj = item as JObject;
if (obj == null)
throw new JsonSerializationException(string.Format("Item \"{0}\" was not a JObject", obj.ToString(Formatting.None)));
var objType = (string)obj[JsonTypeName];
if (objType != null && type == null)
type = objType;
else if (objType != null && type != null)
{
if (type != objType)
throw new JsonSerializationException("Too many item types.");
}
foreach (var property in obj.Properties().Where(p => p.Name != JsonTypeName))
{
if (!properties.ContainsKey(property.Name))
properties.Add(property.Name, properties.Count);
}
}
var propertyList = properties.OrderBy(p => p.Value).Select(p => p.Key).ToArray();
var newValue = new JObject();
if (type != null)
newValue["type"] = JToken.FromObject(typeNameMapper(type));
newValue["structure"] = JToken.FromObject(propertyList);
newValue["list"] = JToken.FromObject(array
.Select(o => (o.Type == JTokenType.Null ? o : propertyList.Where(p => o[p] != null).Select(p => o[p]))));
if (value.Parent != null)
value.Replace(newValue);
return newValue;
}
}
然后,在控制台方法的顶层,您可以按以下步骤修复JSON:
Then, at the top level of your console method, you can fix your JSON as follows:
Func<string, string> typeNameMapper = (t) =>
{
if (!t.EndsWith(", Version=1.2.7.0, Culture=neutral, PublicKeyToken=null"))
t = t + ", Version=1.2.7.0, Culture=neutral, PublicKeyToken=null";
return t;
};
var paths = new[]
{
"channels.heart-rate.events",
"channels.location.events"
};
JsonExtensions.ReformatCollections(inputStream, outputStream, paths, typeNameMapper, Formatting.Indented);
样本小提琴.
这篇关于JSON数据未转换为列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!