You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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包)来手动实现引用替换逻辑。

实现步骤

    1. 将原始JSON解析为JsonNode对象
    1. 递归遍历所有节点,识别包含$ref属性的对象
    1. 通过Json.Path解析$ref中的JSON路径,定位到目标节点
    1. 用目标节点的副本替换原引用节点(避免后续修改影响原节点)

代码示例

首先安装依赖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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 00:06:09