无法反序列化JSON字符串

时间:2018-06-18 19:14:04

标签: c# json json.net deserialization

在我遇到很多麻烦的那一刻,我正在进行的项目。我从外部源获取JSON字符串。我收到的JSON字符串如下:

{
    "PC_Station": [{
        "PLC_0": {
            "DB1": {
                "test123": 0
            },
            "STOP": false,
            "START": false,
            "Start_1": false,
            "Stop_1": false,
            "Led1": true,
            "Led2": false,
            "Led3": true,
            "Counter": 4002,
            "Sliderval": 0
        }
    }, {
        "PLC_1": {
            "DB1": {
                "test123": 0
            },
            "Led_1": false,
            "Led_2": false,
            "Led_3": false,
            "Led_4": false,
            "Tag1": true,
            "Tag2": false,
            "Tag3": true,
            "Counter": 4002,
            "randomNr": 0
        }
    }]
}

外部源的设计方式是PLC设备(工业I / O)将其拥有的所有变量发送到服务器。服务器收集PLC设备的名称及其包含的所有变量,并将所有PLC设备添加到数组中,如上面的JSON中那样。

我需要的是:我试图在C#中创建一个动态捕获所有变量和变量名的JSON反序列化器。我将在我正在进行作业的应用程序中使用它。在Unity3d中用PLC变量填充GUI,但在这种情况下它们是无关的。

我尝试过的最后一件事是:

static void Main(string[] args)
        {
            string json = "{\"PC_Station\": [{\"PLC_0\": {\"DB1\": {\"test123\": 0}, \"STOP\": false, \"START\": false, \"Start_1\": false, \"Stop_1\": false, \"Led1\": true, \"Led2\": false, \"Led3\": true, \"Counter\": 4002, \"Sliderval\": 0}},{\"PLC_1\": {\"DB1\": {\"test123\": 0}, \"STOP\": false, \"START\": false, \"Start_1\": false, \"Stop_1\": false, \"Led1\": true, \"Led2\": false, \"Led3\": true, \"Counter\": 4002, \"Sliderval\": 0}}]}";
            JObject root = JObject.Parse(json);
            dynamic pcstation = root["PC_Station"];
            for(int x = 0; x < pcstation.Count; x++)
            {
                Console.WriteLine(pcstation[x]);
            }
            Console.ReadLine();
        }

当在for循环中仅打印x时,我输出0和1作为输出,这意味着有2个项目,也就是PC_station下阵列中的两个PLC设备。我觉得我几乎就在那里。

我希望任何人都可以帮助我弄清楚我需要做什么,因为我几乎在我的智慧结束。

编辑1:似乎我不清楚我想要什么,你看,我收到的示例JSON代码来自两个随机PLC设备。每个PLC都有自己的变量,因此我不能使用由json2csharp生成的类。我想动态反序列化并使用从服务器收到的变量来在Unity中可视化它们。

6 个答案:

答案 0 :(得分:1)

尝试将两个数组项转换为列表,这样就可以了。我遇到了同样的问题,并且解决了同样的问题。试试,如果它不起作用,请告诉我。我会和你分享代码。

答案 1 :(得分:1)

您可以使用JToken解析此JSON,这样可以轻松地迭代属性和访问对象,而无需事先知道整个结构。

var json = @"{
""PC_Station"": [{
        ""PLC_0"": {
            ""DB1"": {
                ""test123"": 0
            },
            ""STOP"": false,
            ""START"": false,
            ""Start_1"": false,
            ""Stop_1"": false,
            ""Led1"": true,
            ""Led2"": false,
            ""Led3"": true,
            ""Counter"": 4002,
            ""Sliderval"": 0
        }
    }, {
        ""PLC_1"": {
            ""DB1"": {
                ""test123"": 0
            },
            ""Led_1"": false,
            ""Led_2"": false,
            ""Led_3"": false,
            ""Led_4"": false,
            ""Tag1"": true,
            ""Tag2"": false,
            ""Tag3"": true,
            ""Counter"": 4002,
            ""randomNr"": 0
        }
    }]
}";


var root = JToken.Parse(json);
int i = 0;
foreach (var item in root["PC_Station"].Values())
{
    Console.WriteLine("Item {0}: {1}", i++, item);
}

您可以轻松枚举 root JToken对象的属性,例如

static void TraverseJToken(JToken jtoken)
{
    foreach (var value in jtoken.Values())
    {
        if (value.HasValues)
        {
            TraverseJToken(value);
        }
        else
        {
            Console.WriteLine(value.Path + ": " + value.ToObject<string>());
        }
    }
}

TraverseJToken(root);

您还可以选择JSON树的各个值和子集:

var Counter = root.SelectToken("PC_Station[0].PLC_0.Counter").Value<int>();
Console.WriteLine("Counter: " + Counter);

答案 2 :(得分:1)

我想我理解你的问题。如果您无法定义可用于将JSON映射到C#的C#类,那么您需要重新考虑它。为什么不创建一个只有Dictionary<string,string>HashSet<string,string>

的简单C#类

如果您正在设计如何构建PLC的有效负载,那么您可以使其适合具有一些基本属性的简单C#类和不一致创建/可用的变量的字典。

或者如果您想要dynamic类型行为,https://weblog.west-wind.com/posts/2012/Aug/30/Using-JSONNET-for-dynamic-JSON-parsing

答案 3 :(得分:1)

JSON.parse convert json to  object.

Accessing Object Values. You can access the object values by using dot (.)

 for(int x = 0; x < pcstation.Count; x++)
            {
                Console.WriteLine(pcstation[x].PLC_0.DB1.test123);//0
                Console.WriteLine(pcstation[x].STOP);//false

 }

答案 4 :(得分:1)

您可以使用Newtonsoft.json

string line = "{\"PC_Station\": [{\"PLC_0\": {\"DB1\": {\"test123\": 0}, \"STOP\": false, \"START\": false, \"Start_1\": false, \"Stop_1\": false, \"Led1\": true, \"Led2\": false, \"Led3\": true, \"Counter\": 4002, \"Sliderval\": 0}},{\"PLC_1\": {\"DB1\": {\"test123\": 0}, \"STOP\": false, \"START\": false, \"Start_1\": false, \"Stop_1\": false, \"Led1\": true, \"Led2\": false, \"Led3\": true, \"Counter\": 4002, \"Sliderval\": 0}}]}";
var files = JObject.Parse(line);
var recList = files.SelectToken("$..PC_Station").ToList();

    foreach (var item in recList)

    {
        for (int i = 0; i < item.Count(); i++)
        {
            Console.WriteLine(recList[i]);
        }
    }

答案 5 :(得分:0)

设法解决了我的问题!你们共享过时的信息,并编写了大量的代码。但是,嘿,它有效:P。这是我使用此处发布的建议想到的代码:

using Newtonsoft.Json.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using UnityEngine;
using UnityEngine.UI;

public class generateUI : MonoBehaviour
{
    public static int size = 0;
    public static List<Dictionary<string, string>> abc = new List<Dictionary<string, string>>();
    public GameObject canvas;
    public GameObject Panel;
    public GameObject image;
    public GameObject imagetext;
    private float scaler = 0.0125f;
    void Start()
    {
        string json = "{\"PC_Station\": [{\"PLC_0\": {\"DB1\": {\"test123\": 0}, \"STOP\": false, \"START\": false, \"Start_1\": false, \"Stop_1\": false, \"Led1\": true, \"Led2\": false, \"Led3\": true, \"Counter\": 4002, \"Sliderval\": 0}}]}";
        //string json = "{\"PC_Station\": [{\"PLC_0\": {\"DB1\": {\"test123\": 0}, \"STOP\": false, \"START\": false, \"Start_1\": false, \"Stop_1\": false, \"Led1\": true, \"Led2\": false, \"Led3\": true, \"Counter\": 4002, \"Sliderval\": 0}},{\"PLC_1\": {\"DB1\": {\"test123\": 0}, \"STOP\": false, \"START\": false, \"Start_1\": false, \"Stop_1\": false, \"Led1\": true, \"Led2\": false, \"Led3\": true, \"Counter\": 4002, \"Sliderval\": 0}}]}";
        Panel.transform.SetParent(canvas.transform, false);
        var root = JToken.Parse(json);
        IterateJtoken(root);
        List<string> varz = new List<string>();
        foreach(var item in abc)
        {
            foreach(var it in item)
            {
                varz.Add(it.Key);
            }
        }




        GameObject[] tiles = new GameObject[size];
        GameObject[] texts = new GameObject[size];
        int tilenum = 0;
        for (int i = 0; i < size; i++)
        {
            tilenum++;
            tiles[i] = Instantiate(image, transform.position, transform.rotation);
            tiles[i].name = "tile"+tilenum;
            tiles[i].transform.SetParent(Panel.transform, false);
            texts[i] = Instantiate(imagetext, transform.position, transform.rotation);
            texts[i].transform.SetParent(tiles[i].transform, false);
            texts[i].GetComponent<Text>().text = varz[i];
            texts[i].transform.position += new Vector3(55*scaler, -4*scaler, 0);
        }
    }

    public static void test()
    {
        int i = 0;
        foreach(var item in abc)
        {
            foreach(var it in item)
            {
                i++;
            }
        }
        Debug.Log(i);
    }

    public static void IterateJtoken(JToken jtoken)
    {
        foreach (var value in jtoken)
        {
            foreach (JArray test in value)
            {
                for (int i = 0; i < test.Count; i++)
                {
                    foreach (var item in test[i])
                    {
                        var itemproperties = item.Parent;
                        foreach (JToken token in itemproperties)
                        {
                            if (token is JProperty)
                            {
                                var prop = token as JProperty;
                                //Console.WriteLine(prop.Name);           //PLC name
                                var plc = (JObject)prop.Value;
                                Dictionary<string, string> variables = new Dictionary<string, string>();
                                foreach (KeyValuePair<string, JToken> val in plc)
                                {

                                    if (val.Value is JObject)
                                    {
                                        JObject nestedobj = (JObject)val.Value;
                                        foreach (JProperty nestedvariables in nestedobj.Properties())
                                        {
                                            size++;
                                            var nestedVariableName = nestedvariables.Name;
                                            var nestedVariableValue = nestedvariables.Value;
                                            variables.Add(nestedVariableName, nestedVariableValue.ToString());
                                            //Console.WriteLine(nestedVariableName+" "+nestedVariableValue);
                                        }

                                    }
                                    else
                                    {
                                        size++;
                                        var variableName = val.Key;
                                        var variableValue = val.Value;
                                        variables.Add(variableName, variableValue.ToString());
                                        //Console.WriteLine(variableName+" "+variableValue);
                                    }

                                }
                                abc.Add(new Dictionary<string, string>(variables));
                            }
                        }
                    }
                }
            }


        }

    }
}

这是我附加到Unity3D中一个空游戏对象的脚本。我还用面板孩子制作了一个画布(宽:1090,高:430)。我添加了一个网格布局组,其单元大小为100x100,间距为10x10。 画布和面板将被拖到附加到空游戏对象的脚本上。将它们拖到脚本后,您需要制作两个预制件:

  • 100x100的用户界面/图像,颜色为白色

  • UI /文本(160宽度,30高度)

创建完这两个后,将它们拖到空游戏对象附带的脚本中。 现在,当启动Unity3d应用程序时,您会看到一个画布由JSON字符串中所有可用的PLC变量填充。

切换2个字符串以查看其在运行时动态变化(第一个字符串将添加10个元素,第二个字符串将添加20个元素)。

如果有任何清理代码的建议,请告知。