【问题标题】:Having trouble with deserializing a JSON String反序列化 JSON 字符串时遇到问题
【发布时间】:2018-06-18 19:14:03
【问题描述】:

对于我目前正在进行的一个项目,我遇到了很多麻烦。我从外部来源得到一个 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 中可视化它们。

【问题讨论】:

  • 那是什么问题???
  • 试着清理一下,如果仍然不清楚,请告诉我:)

标签: c# json json.net deserialization


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    您可以使用 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);
    

    【讨论】:

      【解决方案3】:
      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
      
       }
      

      【讨论】:

      • c#中的javascript对象?
      • 是的,显然你删除了错误的指令。
      【解决方案4】:

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

      如果您是设计如何构造来自 PLC 的有效负载的人,那么您可以使其适合一个简单的 C# 类,该类具有一些基本属性和一个字典,用于存储并非始终如一地创建/可用的变量。

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

      【讨论】:

        【解决方案5】:

        你可以使用 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]);
                }
            }
        

        【讨论】:

          【解决方案6】:

          设法解决了我的问题!使用你们分享的信息并制作了一堆糟糕的代码。但是,嘿,它有效: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 中附加到空游戏对象的脚本。我还用 Panel Child 制作了 Canvas(width:1090, height:430)。我添加了一个网格布局组,其单元格大小为 100x100,间距为 10x10。 画布和面板将被拖到附加到空游戏对象的脚本中。将它们拖到脚本后,您需要制作两个预制件:

          • 100x100 的 UI/图像,白色

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

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

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

          如果对清理代码有任何建议,请告诉。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2020-10-20
            • 2011-06-30
            • 2021-10-19
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多