如何在 System.Text.Json.Nodes 命名空间中使用 .NET 6 JsonNode 复制 JSON 值?

How to copy a JSON value using .NET 6 JsonNode in System.Text.Json.Nodes namespace?

我有一个简单的 JSON 我想重命名(可能通过复制然后删除)一个密钥。 .NET Fiddle:

        const string input = @"{ ""foo"": [{""a"": 1}, {""b"": null}] }";
        var node = JsonNode.Parse(input);
        Console.WriteLine(node); // Output: the JSON
        Console.WriteLine(node["foo"][0]["a"]); // Output: 1
        
        // How to copy/rename?
        node["bar"] = node["foo"];
        Console.WriteLine(node["bar"][0]["a"]); // Should be 1
{
  "foo": [
    {
      "a": 1
    },
    {
      "b": null
    }
  ]
}

我怎么copy/rename呢?我尝试使用 node["foo"].AsValue() 但效果不佳。错误是

The node must be of type 'JsonValue'


我刚刚通过转换为 JSON 字符串并再次解析它找到了解决方法,但我希望有更好的方法来做到这一点。

node["bar"] = JsonNode.Parse(node["foo"].ToJsonString());

您的问题更新将“栏”添加到现有节点对象。如果你想创建一个新对象,它是现有节点对象的副本, 你可以通过两种主要方式

  1. 最简单有效的方法是改变json字符串
    string newInput = input.Replace("\"foo\":","\"bar\":");
    var newNode=JsonNode.Parse(newInput);
  1. 或创建新的json对象
var newNode = new JsonObject( new[] { KeyValuePair.Create<string,JsonNode>("bar", 
               JsonNode.Parse(node["foo"].ToJsonString()) )});

结果

{
  "bar": [
    {
      "a": 1
    },
    {
      "b": null
    }
  ]
}

所以你有一个 JSON object,所以 JsonNode.Parse 实际上 return 一个 JsonObject,所以首先我们需要转换它:

var jsonObject = JsonNode.Parse(input)!.AsObject(); // null check omitted for brevity

现在让我们重命名。重命名实际上是用旧 属性 删除 object,然后用新名称读取它。所以:

var node = jsonObject["foo"]; // take a reference to foo so we don't lose it
jsonObject.Remove("foo"); // detach from parent
jsonObject.Add("bar", node); // attach with new name

之所以需要先删除再添加,是因为JsonNode object有parent,不允许添加节点到 object 或数组,如果它已经有 parent。因此,您首先需要使用 Remove 将其与 parent 分离,然后您可以使用 Add.

将其添加回新名称下

现在,这修改了原来的 JSON object。如果您想保留原件,则必须先克隆它。这是一个问题,因为没有办法克隆一个JsonNode。你可以这样做:

var clone = new JsonObject(jsonObject);

它会编译,但是在运行时你会遇到异常,因为这只是将节点从一个 object 添加到下一个,正如我们已经确定的那样,你不能添加 object 已经有一个 parent 到另一个。您必须首先克隆每个 child 节点并添加它们。

据我所知,JsonNodes 命名空间无法对 JSON 节点进行深度克隆。这似乎是一个疏忽。您可以通过递归枚举文档中的节点并创建它们来手动完成,或者只解析文档两次。