【问题标题】:Unable to correctly parse JSON body无法正确解析 JSON 正文
【发布时间】:2019-08-27 14:58:20
【问题描述】:

我能够使用 Newtonsoft 库从 Visual Studio 2019 中的 URL 成功检索 JSON 正文。但是,我很难解析出我感兴趣的唯一变量。

我尝试按照这里的一些指南进行操作,但我似乎没有正确实施或没有完全理解(我对此很陌生)。 例如 Unexpected character encountered while parsing API response

原始 JSON:

{"deviceId":37,"longMacAddress":"5884e40000000439","shortMacAddress":259,"hoplist":"(259,3)","associationTime":"2019-06-10 22:43:54","lifeCheckInterval":5,"lastLiveCheck":"2019-06-11 07:11:37","onlineStatus":1,"txPowerValue":14,"deviceType":1,"frequencyBand":1,"lastLivecheck":"2019-06-11 07:11:36","disassociationState":0,"firmwareUpdateActivated":0,"firmwareUpdatePackagesSent":0,"firmwareUpdatePackagesUnsent":0,"firmwareUpdateInProgress":0,"deviceIdOem":"-1","deviceNameOem":"-1","deviceCompanyOem":"-1","binaryInputCount":0,"binaryOutputCount":0,"analogInputCount":0,"characterStringCount":1,"location":[{"location":"UK","locationWriteable":1,"changedAt":"2019-06-10 23:40:50"}],"description":[{"description":"DevKit","descriptionWriteable":1,"changedAt":"2019-06-10 23:40:54"}],"binaryInput":[],"binaryOutput":[],"analogInput":[],"characterString":[{"characterString":"149+0.0+99+26.5+0","characterStringWriteable":1,"changedAt":"2019-06-11 06:45:02"}]}

我的主要代码:

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace API_JSON_1
{
    class Program
    {
        static void Main(string[] args)
        {
            var client = new WebClient();
            var JSON = client.DownloadString("http://192.168.0.254:8000/nodes/longmac/5884e40000000439");
            Console.WriteLine(JSON);
            Console.WriteLine("----------------------------------------------");
            CharacterString CSV = JsonConvert.DeserializeObject<CharacterString>(JSON);
            Console.WriteLine("Sensor data: " + CSV.CharacterStringCharacterString);
        }
    }
}

我的字符串类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace API_JSON_1
{
    public class CharacterStrings
    {
        public CharacterStrings CharString { get; set; }
    }

    public class CharacterString
    {   public string CharacterStringCharacterString { get; set; }
        public long CharacterStringWriteable { get; set; }
        public DateTimeOffset ChangedAt { get; set; }
    }
}

输出到控制台:

{"deviceId":37,"longMacAddress":"5884e40000000439","shortMacAddress":259,"hoplis
t":"(259,3)","associationTime":"2019-06-10 22:43:54","lifeCheckInterval":5,"last
LiveCheck":"2019-06-11 06:56:37","onlineStatus":1,"txPowerValue":14,"deviceType"
:1,"frequencyBand":1,"lastLivecheck":"2019-06-11 06:56:33","disassociationState"
:0,"firmwareUpdateActivated":0,"firmwareUpdatePackagesSent":0,"firmwareUpdatePac
kagesUnsent":0,"firmwareUpdateInProgress":0,"deviceIdOem":"-1","deviceNameOem":"
-1","deviceCompanyOem":"-1","binaryInputCount":0,"binaryOutputCount":0,"analogIn
putCount":0,"characterStringCount":1,"location":[{"location":"UK","locati
onWriteable":1,"changedAt":"2019-06-10 23:40:50"}],"description":[{"description"
:"DevKit","descriptionWriteable":1,"changedAt":"2019-06-10 23:40:54"}],"binaryIn
put":[],"binaryOutput":[],"analogInput":[],"characterString":[{"characterString"
:"149+0.0+99+26.5+0","characterStringWriteable":1,"changedAt":"2019-06-11 06:45:
02"}]}
----------------------------------------------
Sensor data:
Press any key to continue . . .

显然,我期待/希望那里的倒数第二行会显示: "传感器数据:149+0.0+99+26.5+0"

【问题讨论】:

  • 您的CharacterStrings 类有一个属于同一类的属性(CharacterStrings),假设它应该是CharacterString。 CharacterString 也是一个数组,而不是单个项目。
  • 将您的 JSON 粘贴在此处 app.quicktype.io/?l=csharp。它会自动根据您的需要制作模型。
  • Visual Studio 已经能够创建大约 10 年来所需的 JSON 类。另外,解析(标题和正文)和反序列化(代码)是有区别的

标签: c# json visual-studio-2019


【解决方案1】:

为了让它工作,你必须像这样修改你的类:

public class CharacterStrings
{
    public List<CharacterStringObject> CharacterString { get; set; }
}
public class CharacterStringObject
{
    public string CharacterString { get; set; }
    public long CharacterStringWriteable { get; set; }
    public DateTime ChangedAt { get; set; }
}

在那之后,在你这样阅读你的 JSON 之后:

CharacterString CSV = JsonConvert.DeserializeObject<CharacterString>(JSON);

您最终会得到List&lt;CharacterStringObject&gt;,其中包含一个元素。所以你把第一个像这样打印出来:

Console.WriteLine("Sensor data: " + CSV.CharacterString.First().CharacterString);

干杯,
编辑:使用您给定的 JSON 在本地对其进行测试,工作正常

【讨论】:

    【解决方案2】:

    欢迎来到 StackOverflow!

    在将 json 字符串转换为对象(即:反序列化)时需要记住的一点是,要将字符串转换为的对象需要与 json 字符串的格式匹配。在您的情况下,json 字符串与您要转换的对象不匹配。

    一旦你有正确的对象,这会给你你想要的输出:

        static void Main(string[] args)
        {
            string JSON = "{\"deviceId\":37,\"longMacAddress\":\"5884e40000000439\",\"shortMacAddress\":259,\"hoplist\":\"(259,3)\",\"associationTime\":\"2019-06-10 22:43:54\",\"lifeCheckInterval\":5,\"lastLiveCheck\":\"2019-06-11 07:11:37\",\"onlineStatus\":1,\"txPowerValue\":14,\"deviceType\":1,\"frequencyBand\":1,\"lastLivecheck\":\"2019-06-11 07:11:36\",\"disassociationState\":0,\"firmwareUpdateActivated\":0,\"firmwareUpdatePackagesSent\":0,\"firmwareUpdatePackagesUnsent\":0,\"firmwareUpdateInProgress\":0,\"deviceIdOem\":\"-1\",\"deviceNameOem\":\"-1\",\"deviceCompanyOem\":\"-1\",\"binaryInputCount\":0,\"binaryOutputCount\":0,\"analogInputCount\":0,\"characterStringCount\":1,\"location\":[{\"location\":\"UK\",\"locationWriteable\":1,\"changedAt\":\"2019-06-10 23:40:50\"}],\"description\":[{\"description\":\"DevKit\",\"descriptionWriteable\":1,\"changedAt\":\"2019-06-10 23:40:54\"}],\"binaryInput\":[],\"binaryOutput\":[],\"analogInput\":[],\"characterString\":[{\"characterString\":\"149+0.0+99+26.5+0\",\"characterStringWriteable\":1,\"changedAt\":\"2019-06-11 06:45:02\"}]}";
            Console.WriteLine(JSON);
            Console.WriteLine("----------------------------------------------");
            RootObject CSV = JsonConvert.DeserializeObject<RootObject>(JSON);
    
            // Option 1: Loop over the items in your List<CharacterString>...
    
            foreach (var cs in CSV.characterString)
            {
                Console.WriteLine("Sensor data: " + cs.characterString);
            }
    
            // Option 2: Or, if you know there is only one in the list...
    
            Console.WriteLine("Sensor data: " + CSV.characterString.First().characterString);
       }
    

    编辑以解释上面的代码: 因为characterStringList&lt;CharacterString&gt;,所以从技术上讲,您可以在该列表中拥有多个项目。选项 1:如果需要,您可以遍历该列表以显示其中的项目。但是,如果您确定列表中只有一个项目,那么,选项 2:您可以只在列表中显示 .First() 项目。

    我拿走了你给我们的 json 刺痛,并使用这个方便的网站 (http://json2csharp.com/#) 将其转换为以下类:

    public class RootObject
    {
        public int deviceId { get; set; }
        public string longMacAddress { get; set; }
        public int shortMacAddress { get; set; }
        public string hoplist { get; set; }
        public string associationTime { get; set; }
        public int lifeCheckInterval { get; set; }
        public string lastLiveCheck { get; set; }
        public int onlineStatus { get; set; }
        public int txPowerValue { get; set; }
        public int deviceType { get; set; }
        public int frequencyBand { get; set; }
        public string lastLivecheck { get; set; }
        public int disassociationState { get; set; }
        public int firmwareUpdateActivated { get; set; }
        public int firmwareUpdatePackagesSent { get; set; }
        public int firmwareUpdatePackagesUnsent { get; set; }
        public int firmwareUpdateInProgress { get; set; }
        public string deviceIdOem { get; set; }
        public string deviceNameOem { get; set; }
        public string deviceCompanyOem { get; set; }
        public int binaryInputCount { get; set; }
        public int binaryOutputCount { get; set; }
        public int analogInputCount { get; set; }
        public int characterStringCount { get; set; }
        public List<Location> location { get; set; }
        public List<Description> description { get; set; }
        public List<object> binaryInput { get; set; }
        public List<object> binaryOutput { get; set; }
        public List<object> analogInput { get; set; }
        public List<CharacterString> characterString { get; set; }
    }
    
    public class Location
    {
        public string location { get; set; }
        public int locationWriteable { get; set; }
        public string changedAt { get; set; }
    }
    
    public class Description
    {
        public string description { get; set; }
        public int descriptionWriteable { get; set; }
        public string changedAt { get; set; }
    }
    
    public class CharacterString
    {
        public string characterString { get; set; }
        public int characterStringWriteable { get; set; }
        public string changedAt { get; set; }
    }
    

    【讨论】:

    • 感谢您的建议,我会试一试。您能解释一下以下几行的作用吗?我认为它有两种实现相同结果的方法:foreach (var cs in CSV.characterString) { Console.WriteLine("Sensor data: " + cs.characterString); } // or Console.WriteLine("Sensor data: " + CSV.characterString.First().characterString);
    • @23deano,是的,你是对的 :) 假设列表中只有一个项目,那么这两个项目都会做同样的事情。但是,如果列表中有多个项目,则使用第二个选项时,将仅显示列表中的第一个项目,而忽略所有其他项目。因为CSV.characterStringList&lt;CharacterString&gt;,它可能在列表中有多个项目。但是当你在上面调用.First() 时,你要求的是第一个,并且只有第一个项目。我还编辑了我的答案以更好地解释。
    • 再次感谢!我已经能够实施您建议的更改,现在我可以从应用程序中获得我需要的输出。我需要弄清楚反序列化是如何工作的。它需要RootObject,这是所有原始 JSON 布局到其单独的类中,并将其放入变量 CSV。从那里我们可以将characterString 数组的第一个(或第二个或第三个等)元素写入控制台。 (我认为在我的第一次尝试中,我也有太多的对象、数组和元素的名称太相似,这没有帮助)。
    • 反序列化和序列化真的很简单。在 JSON 的情况下,它们只需要一个字符串并将其转换为一个对象,反之亦然。在您的情况下,RootObject(如果您愿意,您可以更改该名称)只是一个与您的 json 字符串具有所有相同属性的类。所以两者之间的映射很简单。 Newtonsoft 让它变得超级简单。获取一个 json 字符串并将其转换(即:反序列化)为 RootObject'. C# can't really do much with a string. But it can do a LOT with RootObject` 的实例。
    【解决方案3】:

    json 中的 CharacterString 属性是一个对象数组。这些对象中的第一个属性也是characterString。下面是一个工作示例

    输出为Sensor Data: 149+0.0+99+26.5+0

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Newtonsoft.Json;
    
    namespace SOTest
    {
        class Program
        {
            static void Main(string[] args)
            {
                var json =
                    "{\"deviceId\":37,\"longMacAddress\":\"5884e40000000439\",\"shortMacAddress\":259,\"hoplist\":\"(259,3)\",\"associationTime\":\"2019-06-10 22:43:54\",\"lifeCheckInterval\":5,\"lastLiveCheck\":\"2019-06-11 07:11:37\",\"onlineStatus\":1,\"txPowerValue\":14,\"deviceType\":1,\"frequencyBand\":1,\"lastLivecheck\":\"2019-06-11 07:11:36\",\"disassociationState\":0,\"firmwareUpdateActivated\":0,\"firmwareUpdatePackagesSent\":0,\"firmwareUpdatePackagesUnsent\":0,\"firmwareUpdateInProgress\":0,\"deviceIdOem\":\"-1\",\"deviceNameOem\":\"-1\",\"deviceCompanyOem\":\"-1\",\"binaryInputCount\":0,\"binaryOutputCount\":0,\"analogInputCount\":0,\"characterStringCount\":1,\"location\":[{\"location\":\"UK\",\"locationWriteable\":1,\"changedAt\":\"2019-06-10 23:40:50\"}],\"description\":[{\"description\":\"DevKit\",\"descriptionWriteable\":1,\"changedAt\":\"2019-06-10 23:40:54\"}],\"binaryInput\":[],\"binaryOutput\":[],\"analogInput\":[],\"characterString\":[{\"characterString\":\"149+0.0+99+26.5+0\",\"characterStringWriteable\":1,\"changedAt\":\"2019-06-11 06:45:02\"}]}";
    
                var obj = JsonConvert.DeserializeObject<CharacterStrings>(json);
                Console.WriteLine($"Sensor Data: {obj.CharacterString.First().CharacterString}");
                Console.ReadKey();
            }
    
            public class CharacterStrings
            {
                public List<Characters> CharacterString { get; set; }
            }
    
            public class Characters
            {   public string CharacterString { get; set; }
                public long CharacterStringWriteable { get; set; }
                public DateTime ChangedAt { get; set; }
            }
        }
    }
    

    【讨论】:

    • 如果我按照您的建议更改public class CharacterStrings,我会收到一条错误消息:public string Character String { get; set; } 显示为'CharacterString': member names cannot be the same as their enclosing type
    • 我更正了这一点,因为您不能拥有与类同名的属性。上面的例子正在运行
    【解决方案4】:

    您正在使用 CharacterSting 定义 CSV 对象。我应该是 CharacterStrings 并且在 CharacterStrings 类中它应该是数组,因为您的 JSON 是一个数组

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-04-02
      • 1970-01-01
      • 2020-07-24
      • 2019-03-01
      • 2018-05-17
      • 2021-02-26
      • 2013-10-14
      • 2012-08-12
      相关资源
      最近更新 更多