使用Linq查询在JObject中查找放置在同一作业对象外部的数组属性



我有一个JObject的列表,每个JObject都包含一个属性调用"roles",即JArray的类型。

因此,我尝试迭代JArray值,并将一个角色对象匹配到外部JObject(Test,Test2(中,最后返回JObject的列表。

作业项目输入列表:

[
{
"SchemaName":"Test",
"roles":[
{
"role":"create",
"permission":{
"create":true
}
},
{
"role":"read",
"permission":{
"read":true
}
}
]
},
{
"SchemaName":"Test2",
"roles":[
{
"role":"update",
"permission":{
"create":true
}
},
{
"role":"read",
"permission":{
"read":true
}
}
]
}
]

在这个列表中,我必须将名为roleName的变量的记录值匹配为"read"。因此,所有包含'roles'JArray Jobject角色属性值为'read'的Jobject(Test,Test2(,构造新的结构JObject并返回JObject的列表。

到目前为止,我尝试了linq查询,但仍然没有成功。这是代码

using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var jsonString = "[{"SchemaName":"Test","roles":[{"role":"create","permission":{"create":true}},{"role":"read","permission":{"read":true}}]},{"SchemaName":"Test2","roles":[{"role":"update","permission":{"update":true}},{"role":"read","permission":{"read":false}}]}]";

JArray schemaArray = JArray.Parse(jsonString);
string roleName="read";
var matchedSchemasObjectForRole = (from schemaObject in schemaArray 
where 
schemaObject["roles"] != null 
&& JArray.Parse(schemaObject["roles"].ToString()).Count > 0 
&& JArray.Parse(schemaObject["roles"].ToString()).Any(x => x != null && x["role"].ToString() == roleName.ToString()?(schemaObject["role"]=roleName;schemaObject["permissions"]=x["permissions"]):x)
select schemaObject).ToList();

Console.WriteLine(JsonConvert.SerializeObject(matchedSchemasObjectForRole));
}
}

预期结果:

[
{
"SchemaName":"Test",
"role":"read",
"permission":{
"read":true
}
},
{
"SchemaName":"Test2",
"role":"read",
"permission":{
"read":false
}
}
]

如何获得预期结果?提前谢谢。

您可以实现如下所需的输出:

List<Schema> reducedSchemas = new List<Schema>();
const string RolesArrayName = "roles", RoleNodeName = "role", SchemaNodeName = "SchemaName";
string roleFilter = "read"; //Let's pretend that this value is received from user
var schemaArray = JArray.Parse(jsonString);
foreach (JObject schema in schemaArray)
{
if (!schema.ContainsKey(RolesArrayName)) continue;
var roles = (JArray)schema[RolesArrayName];
foreach (JObject role in roles)
{
if (!role.TryGetValue(RoleNodeName, out var roleNameToken)) continue;
var roleName = (string)roleNameToken;
if (!string.Equals(roleName, roleFilter, StringComparison.InvariantCultureIgnoreCase)) continue;
reducedSchemas.Add(new Schema {
Name = (string)schema[SchemaNodeName],
Role = roleName,
Permission = new Permission() });
}
}
  • JArray.Parse调用之后,我们可以遍历半解析数组
    • 请注意,如果您要编写foreach (var schema in schemaArray),那么schema的类型将是JToken,但因为我们需要JObject,所以我们应该明确地说
  • 我们使用ContainsKey来确保给定节点存在
    • 尽管我们也可以在这里使用TryGetValue,但感觉有点笨拙,因为TryGetValue的输出是JToken,需要转换为JArray
  • 每当我们有了roles,我们就可以用与schemaArray相同的技巧迭代它们
  • 如果该节点与TryGetValue一起存在,我们尝试获得role
  • 提取值后,我们可以将读取的值与用户给定的值进行比较
  • 如果它们匹配,那么我们只需向reducedSchemas集合添加一个新的Schema对象

Schema可以像这样定义

class Schema
{
[JsonProperty("SchemaName")]
public string Name { get; set; }
[JsonProperty("role")]
public string Role { get; set; }
[JsonProperty("permission")]
public Permission Permission { get; set; }
}
class Permission
{
[JsonProperty("read")]
public bool CanRead { get; set; }
}

更新根据注释修订代码

我已经将Permission类的定义更改为:

class Permission
{
[JsonProperty("granted")]
public bool HasGranted { get; set; }
}

这表示是否已授予访问权限
您可以随意将其重命名为任何套房

修改后的解析逻辑如下:

var reduced = new List<Schema>();
const string RolesArrayName = "roles", RoleNodeName = "role",
SchemaNodeName = "SchemaName", PermissionNodeName =  "permission";
string roleFilter = "read";
JArray schemas = JArray.Parse(jsonString);
foreach (JObject schema in schemas)
{
if (!schema.ContainsKey(RolesArrayName)) continue;
foreach (JObject role in (JArray)schema[RolesArrayName])
{
if (!role.TryGetValue(RoleNodeName, out var roleNameToken)) continue;
string roleName = (string)roleNameToken;
if (!string.Equals(roleName, roleFilter, StringComparison.InvariantCultureIgnoreCase)) continue;
if (!role.TryGetValue(PermissionNodeName, out var permission)) continue;
if (!((JObject)permission).TryGetValue(roleFilter, out var granted)) continue;
reduced.Add(new Schema
{
Name = (string)schema[SchemaNodeName],
Role = roleName,
Permission = new Permission
{
HasGranted = (bool)granted
}
});
}
}

可能还有其他可能的方法,但以下是我如何实现的代码。。。

解析逻辑

string roleName="read";
var matchedSchemasObjectForRole =schemaArray.Where(schemaObject => schemaObject["roles"] != null && JArray.Parse(schemaObject["roles"].ToString()).Count > 0
&& JArray.Parse(schemaObject["roles"].ToString()).Any(x => x != null && x["role"]!=null && x["role"].ToString() == roleName.ToString())).Select(schemaObject => new ApplicationRolesCommon()
{                               
RoleName = roleName
permissions = JArray.Parse(schemaObject["roles"].ToString()).Where(s => s["role"].ToString() == roleName.ToString() && s["permissions"]!=null).Select(s => new AppRoleFormSchemaPermissions
{
create = s["permissions"]["create"] !=null ? s["permissions"]["create"].ToObject<bool>() : false,
read = s["permissions"]["read"] != null ? s["permissions"]["read"].ToObject<bool>() : false,
update = s["permissions"]["update"] != null ? s["permissions"]["update"].ToObject<bool>() : false,
delete = s["permissions"]["delete"] != null ? s["permissions"]["delete"].ToObject<bool>() : false
}).First(),
SchemaName = schemaObject["SchemaName"].ToString()
}).ToList();   

域模型

public class ApplicationRolesCommon
{
public string RoleName { get; set; }
public string SchemaName { get; set; }
public AppRoleFormSchemaPermissions permissions { get; set; }
}
public class AppRoleFormSchemaPermissions
{
public bool create { get; set; }
public bool read { get; set; }
public bool update { get; set; }
public bool delete { get; set; }
}

相关内容

  • 没有找到相关文章

最新更新