JSON数据未转换为列表 [英] Json data not converting to List

查看:154
本文介绍了JSON数据未转换为列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个未正确序列化的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:

  • 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 inputStreamStream 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆