c# - 将 json 对象转换为仅具有属性子集的类型化对象
问题描述
我正在选择一个 json 对象,如下所示:
var gridRenderer = json.SelectToken("$..gridRenderer").FirstOrDefault();
上面的行给出了问题末尾显示的 JSON 的以下子集:
{
"items": [
{
"gridVideoRenderer": { } // Many properties omitted.
},
// Other entries omitted.
位于路径:
contents.twoColumnBrowseResultsRenderer.tabs[0].tabRenderer.content.sectionListRenderer.contents[0].itemSectionRenderer.contents[0].gridRenderer
正如您在上面看到的,有很多数据。我想将其转换为具有一组属性的类型化对象:
var ee = gridRenderer.Cast<GridRenderSection>();
首先,我只想获得一个带有 videoid 对象的数组。我有以下课程:
[JsonObject("gridRenderSection")]
public class GridRenderSection
{
[JsonProperty("items")]
public List<GridVideoRenderer> Items{ get; set; }
}
public class GridVideoRenderer
{
[JsonProperty("videoId")]
public string VideoId { get; set; }
}
但我收到以下错误:“无法将'Newtonsoft.Json.Linq.JArray'类型的对象转换为'GridRenderSection'。”
通常你可以转换类型对象的子集,这对于 Cast 函数是不可能的,还是我在这里遗漏了什么?
示例代码(请注意,您可以在示例代码或下面提供的链接上看到 json):
var jsonStr = string.Empty;
using (WebClient client = new WebClient())
{
jsonStr = client.DownloadString("https://srv-file2.gofile.io/download/J1iBAd/json1.json");
}
var json = JObject.Parse(jsonStr);
var gridRenderer = json.SelectToken("$..gridRenderer").FirstOrDefault();
var ee = gridRenderer.Cast<GridRenderSection>();
JSON:
{
"contents": {
"twoColumnBrowseResultsRenderer": {
"tabs": [
{
"tabRenderer": {
"title": "Videoer",
"selected": true,
"content": {
"sectionListRenderer": {
"contents": [
{
"itemSectionRenderer": {
"contents": [
{
"gridRenderer": {
"items": [
{
"gridVideoRenderer": {
"videoId": "lzSlEtuHgAU"
}
},
{
"gridVideoRenderer": {
"videoId": "F5Opl1llzWw"
}
}
]
}
}
]
}
}
]
}
}
}
}
]
}
}
}
解决方案
你在这里有几个问题:
您的查询
json.SelectToken("$..gridRenderer")
返回一个JToken
对应于以下 JSON 对象的单个:{ "items": [ { "gridVideoRenderer": { "videoId": "lzSlEtuHgAU" } }, { "gridVideoRenderer": { "videoId": "F5Opl1llzWw" } } ] }
您正在尝试将其强制转换为 a
GridRenderSection
,但JToken
没有显式或隐式类型转换为任意类型 - 仅转换为简单IConvertible
类型。相反,您需要反序列化以GridRenderSection
使用ToObject<GridRenderSection>()
:var ee = gridRenderer.ToObject<GridRenderSection>();
您要求
FirstOrDefault()
从以下位置返回SelectToken()
:json.SelectToken("$..gridRenderer").FirstOrDefault();
但是,
SelectToken()
已经返回了一个与查询匹配的单曲JToken
,在本例中为 aJObject
。(如果有多个匹配项,则SelectToken()
抛出异常。)稍后,当您.FirstOrDefault()
获取对象的第一个属性并尝试将单个属性反序列化到您的数据模型中时,这是错误的。一般来说,如果您正在调用
SelectToken()
,则无需调用.FirstOrDefault()
;它更常应用于SelectTokens()
可能有很多匹配并且只需要第一个匹配的情况。您的数据模型与您的 JSON 不匹配。
videoId
嵌套在gridVideoRenderer
需要像这样建模的容器对象中:public class GridRenderSection { [JsonProperty("items")] public List<GridRenderSectionItem> Items{ get; set; } } public class GridRenderSectionItem { public GridVideoRenderer gridVideoRenderer { get; set; } } public class GridVideoRenderer { [JsonProperty("videoId")] public string VideoId { get; set; } }
顺便说一句,如果您只需要这些videoId
值,则可以使用以下SelectTokens()
查询直接提取它们:
var videoIds = json.SelectTokens("$..gridRenderer.items[*].gridVideoRenderer.videoId")
.Select(t => t.ToString())
.ToList();
或者,如果您只想要一个GridVideoRenderer
对象列表:
var renderers = json.SelectTokens("$..gridRenderer.items[*].gridVideoRenderer")
.Select(t => t.ToObject<GridVideoRenderer>())
.ToList();
演示固定小提琴here。
推荐阅读
- python-2.7 - 当我从示例中运行此代码时,Android 应用程序崩溃
- sql - 有冒号搜索框时如何启用多个变量进行搜索
- c# - 从 KeePass 获取密码
- c# - TextBox.Text 正在被处理,即使再次创建表单也是如此
- react-native - 平面列表滚动位置 onScroll
- python - 逐字输入并输出一个句子
- java - 如何使标志在 24 小时后自动更改
- python - python tkinter-多个窗口来显示和执行不同的进程
- django - 如何从 Django 中的 ManyToManyField 计算查询集?
- nginx - 为什么我的网站在启用 http/2 时不使用 http/2