使用System.Text.Json.Nodes的JsonNode.Parse能否解析JSON引用?
解析JSON引用:System.Text.Json.Nodes + Json.Path实现方案
JsonNode.Parse方法本身不支持自动解析JSON Schema的$ref引用,没有内置配置开关可以直接替换引用内容。但可以结合System.Text.Json.Nodes的节点操作能力和Json.Path库(需单独安装NuGet包)来手动实现引用替换逻辑。
实现步骤
- 将原始JSON解析为
JsonNode对象
- 将原始JSON解析为
- 递归遍历所有节点,识别包含
$ref属性的对象
- 递归遍历所有节点,识别包含
- 通过
Json.Path解析$ref中的JSON路径,定位到目标节点
- 通过
- 用目标节点的副本替换原引用节点(避免后续修改影响原节点)
代码示例
首先安装依赖NuGet包:
Install-Package Json.Path
C#实现代码:
using System.Text.Json.Nodes; using Json.Path; public static JsonNode ResolveJsonReferences(JsonNode rootNode) { // 递归遍历节点,处理所有$ref引用 void TraverseAndResolve(JsonNode parentNode, string parentProperty = null) { if (parentNode is JsonObject obj) { // 先收集所有$ref节点,避免遍历过程中修改集合导致异常 var refEntries = obj.Where(kv => kv.Key == "$ref" && kv.Value is JsonValue refValue) .ToList(); foreach (var (key, refValue) in refEntries) { var refPath = refValue.ToString(); // 解析JSON路径 var path = JsonPath.Parse(refPath); // 在根节点中查找目标节点 var matchResult = path.Evaluate(rootNode); if (matchResult.Success && matchResult.Matches.Count > 0) { var targetNode = matchResult.Matches[0].Value; // 替换$ref所在的对象为目标节点的副本 if (parentProperty != null && parentNode is JsonObject parentObj) { parentObj[parentProperty] = targetNode.DeepClone(); } } // 移除$ref属性 obj.Remove(key); } // 遍历当前对象的所有子节点 foreach (var kv in obj.ToList()) { TraverseAndResolve(kv.Value, kv.Key); } } else if (parentNode is JsonArray array) { // 遍历数组中的每个元素 for (int i = 0; i < array.Count; i++) { TraverseAndResolve(array[i], i.ToString()); if (array[i] is JsonObject arrayObj && arrayObj.ContainsKey("$ref")) { var refValue = arrayObj["$ref"].ToString(); var path = JsonPath.Parse(refValue); var matchResult = path.Evaluate(rootNode); if (matchResult.Success && matchResult.Matches.Count > 0) { array[i] = matchResult.Matches[0].Value.DeepClone(); } } } } } // 克隆根节点,避免修改原始输入 var clonedRoot = rootNode.DeepClone(); TraverseAndResolve(clonedRoot); return clonedRoot; } // 使用示例 var jsonString = @" { ""firstName"": ""John"", ""lastName"": ""Doe"", ""age"": 21, ""familyTree"": { ""$ref"": ""#/parents"" }, ""parents"": { ""father"": ""Bruce Doe"", ""mother"": ""Mary Doe"" } }"; var originalNode = JsonNode.Parse(jsonString); var resolvedNode = ResolveJsonReferences(originalNode); Console.WriteLine(resolvedNode.ToJsonString(new JsonSerializerOptions { WriteIndented = true }));
注意事项
- 上述代码仅处理根节点内的绝对路径引用(
#/xxx格式),如需支持相对路径或外部引用,需额外扩展逻辑 - 使用
DeepClone()确保替换后的节点是独立副本,避免原节点和替换节点共享引用导致意外修改 Json.Path库支持标准JSON Path语法,可处理复杂路径定位
内容的提问来源于stack exchange,提问作者Cliff Pennalligen
相关产品推荐
相关产品推荐

