为什么当我调用JsonConvert.DeserializeObject时将JArray分配给var失败?

问题描述

在这一行代码上:

var arr = JsonConvert.DeserializeObject<JArray>(s);

...我得到的是,“ 无法将类型为'Newtonsoft.Json.Linq.JObject'的对象转换为类型为'Newtonsoft.Json.Linq.JArray'。”

我将该行更改为此:

JArray arr = JsonConvert.DeserializeObject<JArray>(s);      

...并获得相同的错误信息。

我将其更改为:

var arr = JsonConvert.DeserializeObject<JObject>(s);

...甚至无法编译。

此时调用已读取的内容(在字符串s中)为:

{"id":347745,"results":[{"iso_3166_1":"US","release_dates":[{"certification":"","iso_639_1":"","note":"","release_date":"1936-12-12T00:00:00.000Z","type":3}]}]}

我所需要的只是“认证”的值;在这种情况下,证书值为空字符串(“ certification”:“”)

在上下文中,代码为:

. . .
try
{
    var webRequest = (HttpWebRequest)WebRequest.Create(RESTStringToGetMPAARatingForMovieId);
    webRequest.Method = "GET";  
    var webResponse = (HttpWebResponse)webRequest.GetResponse();
    if ((webResponse.StatusCode == HttpStatusCode.OK) && (webResponse.ContentLength > 0))
    {
        StreamReader streamReader = new StreamReader(webResponse.GetResponseStream());
        string s = streamReader.ReadToEnd();
        var arr = JsonConvert.DeserializeObject<JArray>(s);
        //JArray arr = JsonConvert.DeserializeObject<JArray>(s);
        //var arr = JsonConvert.DeserializeObject<JObject>(s);
        foreach (JObject obj in arr)
        {
            _currentMPAARating = (string)obj["certification"];
            . . .
        }
    }
    else
    {
        MessageBox.Show(string.Format("Status code == {0},Content length == {1}",webResponse.StatusCode,webResponse.ContentLength));
    }    
}
catch (Exception ex)
{
    MessageBox.Show(ex.Message);
}

解决方法

您的JSON不是数组,它是包含数组(results)的对象。但这实际上比这更复杂:您要搜索的certification字符串被嵌套在另一个release_dates数组中。

如果您使用JSON并使用JSON验证器/美化器将其重新格式化,则它应该变得更加清晰:

{
  "id": 347745,"results": [
    {
      "iso_3166_1": "US","release_dates": [
        {
          "certification": "","iso_639_1": "","note": "","release_date": "1936-12-12T00:00:00Z","type": 3
        }
      ]
    }
  ]
}

因此,要使用常规foreach循环获取所需的数据,您将需要以下代码:

var obj = JsonConvert.DeserializeObject<JObject>(s);
var resultArr = (JArray)obj["results"];
foreach (JObject resultObj in resultArr)
{
    var releaseDatesArr = (JArray)resultObj["release_dates"];
    foreach (JObject releaseDateObj in releaseDatesArr)
    {
        _currentMPAARating = (string)releaseDateObj["certification"];
        // ...
    }
}

提琴:https://dotnetfiddle.net/SMzQTw

如果您只需要一项,这里是一个快捷方式。像这样将SelectToken方法与递归下降运算符(..)结合使用:

var obj = JsonConvert.DeserializeObject<JObject>(s);
_currentMPAARating = (string)obj.SelectToken("..certification");

提琴:https://dotnetfiddle.net/S1ScLO

但是请注意,上面只会返回第一个匹配项。如果您希望获得多个认证,则可以改用SelectTokens(复数):

var obj = JsonConvert.DeserializeObject<JObject>(s);
var ratings = obj.SelectTokens("..certification").Select(t => (string)t).ToList();

提琴:https://dotnetfiddle.net/zyjNnJ

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...