gpt4 book ai didi

c# 解析azure策略规则json以制作一棵树

转载 作者:行者123 更新时间:2023-12-03 05:43:42 24 4
gpt4 key购买 nike

我想通过转到每个根级别将 JSON 使用 Newtonsoft.Json.Linq 解析为树格式。

我面临的实际问题是 allOf 内的内容没有被打印,并且在 JObject 中出现 InvalidCast 异常。我需要帮助来打印控制台应用程序中的所有父元素和子元素。

这是 JSON:

{
"properties": {
"displayName": "Audit if Key Vault has no virtual network rules",
"policyType": "Custom",
"mode": "Indexed",
"description": "Audits Key Vault vaults if they do not have virtual network service endpoints set up. More information on virtual network service endpoints in Key Vault is available here: _https://learn.microsoft.com/en-us/azure/key-vault/key-vault-overview-vnet-service-endpoints",
"metadata": {
"category": "Key Vault",
"createdBy": "",
"createdOn": "",
"updatedBy": "",
"updatedOn": ""
},
"parameters": {},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.KeyVault/vaults"
},
{
"anyOf": [
{
"field": "Microsoft.KeyVault/vaults/networkAcls.virtualNetworkRules[*].id",
"exists": "false"
},
{
"field": "Microsoft.KeyVault/vaults/networkAcls.virtualNetworkRules[*].id",
"notLike": "*"
},
{
"field": "Microsoft.KeyVault/vaults/networkAcls.defaultAction",
"equals": "Allow"
}
]
}
]
},
"then": {
"effect": "audit"
}
}
},
"id": "/subscriptions/xxxxxx/providers/Microsoft.Authorization/policyDefinitions/wkpolicydef",
"type": "Microsoft.Authorization/policyDefinitions",
"name": "xyz"
}

我的代码:

static JmesPath jmes = new JmesPath();
static void Main(string[] args)
{
string policyStr = "JSON GIVEN IN THE DESCRIPTION";
string str = jmes.Transform(policyStr, "properties.policyRule.if");
Convert(str);
}

public static void Convert(string json)
{
dynamic myObj = JsonConvert.DeserializeObject(json);
PrintObject(myObj, 0);

Console.ReadKey();
}

private static void PrintObject(JToken token, int depth)
{
if (token is JProperty)
{
var jProp = (JProperty)token;
var spacer = string.Join("", Enumerable.Range(0, depth).Select(_ => "\t"));
var val = jProp.Value is JValue ? ((JValue)jProp.Value).Value : "-";

Console.WriteLine($"{spacer}{jProp.Name} -> {val}");


foreach (var child in jProp.Children())
{
PrintObject(child, depth + 1);
}
}
else if (token is JObject)
{
foreach (var child in ((JObject)token).Children())
{
PrintObject(child, depth + 1);
}
}
}

我已经安装了 JMESPath.Net NuGet 包。演示 fiddle here .

最佳答案

您的基本问题是,在 PrintObject(JToken token, int height) 中,您没有考虑传入 tokenJArray 的情况。 :

if (token is JProperty)
{
}
else if (token is JObject)
{
}
// Else JArray, JConstructor, ... ?

由于 "allOf" 的值是一个数组,因此您的代码不执行任何操作:

{
"allOf": [ /* Contents omitted */ ]
}

最小的修复方法是检查 JContainer然而,这不是 JObject ,它不能处理包含原始值的数组的情况,因此不能被视为正确的修复。 (演示 fiddle #1 here 。)

相反,在递归代码中,您需要处理 JContainer 的所有可能子类,包括 JObjectJArrayJProperty 和(也许)JConstructor。然而,具有两层层次结构的 JObject 和只有一层层次结构的 JArray 之间的不一致,可能会让编写此类递归代码变得烦人。

以更清晰的方式处理数组和对象的一种可能的解决方案是完全隐藏 JProperty 的存在,并表示对象是其子级按名称索引的容器,而数组是其子级按名称索引的容器。按整数索引。以下扩展方法可以完成这项工作:

public interface IJTokenWorker
{
bool ProcessToken<TConvertible>(JContainer parent, TConvertible index, JToken current, int depth) where TConvertible : IConvertible;
}

public static partial class JsonExtensions
{
public static void WalkTokens(this JToken root, IJTokenWorker worker, bool includeSelf = false)
{
if (worker == null)
throw new ArgumentNullException();
DoWalkTokens<int>(null, -1, root, worker, 0, includeSelf);
}

static void DoWalkTokens<TConvertible>(JContainer parent, TConvertible index, JToken current, IJTokenWorker worker, int depth, bool includeSelf) where TConvertible : IConvertible
{
if (current == null)
return;
if (includeSelf)
{
if (!worker.ProcessToken(parent, index, current, depth))
return;
}
var currentAsContainer = current as JContainer;
if (currentAsContainer != null)
{
IList<JToken> currentAsList = currentAsContainer; // JContainer implements IList<JToken> explicitly
for (int i = 0; i < currentAsList.Count; i++)
{
var child = currentAsList[i];
if (child is JProperty)
{
DoWalkTokens(currentAsContainer, ((JProperty)child).Name, ((JProperty)child).Value, worker, depth+1, true);
}
else
{
DoWalkTokens(currentAsContainer, i, child, worker, depth+1, true);
}
}
}
}
}

然后你的 Convert() 方法现在变成:

class JTokenPrinter : IJTokenWorker
{
public bool ProcessToken<TConvertible>(JContainer parent, TConvertible index, JToken current, int depth) where TConvertible : IConvertible
{
var spacer = new String('\t', depth);
string name;
string val;

if (parent != null && index is int)
name = string.Format("[{0}]", index);
else if (parent != null && index != null)
name = index.ToString();
else
name = "";

if (current is JValue)
val = ((JValue)current).ToString();
else if (current is JConstructor)
val = "new " + ((JConstructor)current).Name;
else
val = "-";

Console.WriteLine(string.Format("{0}{1} -> {2}", spacer, name, val));
return true;
}
}

public static void Convert(string json)
{
var root = JsonConvert.DeserializeObject<JToken>(json);
root.WalkTokens(new JTokenPrinter());
}

演示 fiddle #2 here ,输出:

allOf   -> -
[0] -> -
field -> type
equals -> Microsoft.KeyVault/vaults
[1] -> -
anyOf -> -
[0] -> -
field -> Microsoft.KeyVault/vaults/networkAcls.virtualNetworkRules[*].id
exists -> false
[1] -> -
field -> Microsoft.KeyVault/vaults/networkAcls.virtualNetworkRules[*].id
notLike -> *
[2] -> -
field -> Microsoft.KeyVault/vaults/networkAcls.defaultAction
equals -> Allow

相关:

关于c# 解析azure策略规则json以制作一棵树,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56566651/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com