如何使用System.Text.Json库在现有的JSON中添加属性?

22
       {
          "TestData":{
              "Year__of__Account":"2019",
              "Tax___x0025_":"0.06",
              "Buildings__1":"1000",
              "Contents__1":"400",
              "Total_Insurable_Value":"100",
              "Buildings__Prem":"2560.8",
              "Contents__Prem":"1707.2",
              "YB__1":"1950",
              "No__Buildings":"55",
              "Location_Sprinklers_YN":"No",
              "test":"test"
           }
        }

在上面的 JSON 示例中,我想要在 "TestData" 属性内添加一个名为 "Name" 值为 "John" 的属性。我如何使用 .net Core 3.0 System.Text.Json 库实现这一点。

我尝试使用 Utf8JsonWriter 的方法,但它创建了一个新的 JSON 对象,而不是将其附加到上述现有 JSON 中。

        using (MemoryStream memoryStream1 = new MemoryStream())
        {
            using (Utf8JsonWriter utf8JsonWriter1 = new Utf8JsonWriter(memoryStream1))
            {
                using (JsonDocument jsonDocument = JsonDocument.Parse(json))
                {
                    utf8JsonWriter1.WriteStartObject();
                    utf8JsonWriter1.WritePropertyName("Name");
                    utf8JsonWriter1.WriteStringValue("John");
                    utf8JsonWriter1.WriteEndObject();

                    // how can I add above properties to JsonDocument object??
                }
            }
        }

我个人还没有安装VS2019/Core3,所以我自己还没有做过这个,但是你可以像平常一样使用JsonDocument.Parse()来加载文档,添加新属性,然后使用JsonDocument.WriteTo()将其写出。 - 500 - Internal Server Error
是的,这正是我的问题,我如何在加载JsonDocument后添加新属性?我在他们的文档中找不到任何方法。 - Kunal Patil
JsonDocument 是只读的。有一个开放问题 Writable Json DOM #39922 进行跟踪。相关但不重复的问题:使用 System.Text.Json 修改 JSON 文件 - dbc
你能解决这个问题吗?我在插入指定位置的属性时遇到了问题,所以想知道你是否能帮忙回答以下这个问题。我可以使用Newtonsoft或System.Text.Json。 - learner
1
你不能使用System.Text.Json添加属性。请使用Newtonsoft JObject向您的Json对象添加属性。请参考此链接 -> JObject - Kunal Patil
5个回答

19

从 .NET 6 开始,您可以使用 JsonNode。这是一个可修改的、基于字典的 API,用于补充只读的 JsonDocument。

对于您的示例,解决方案如下:

var jsonNode = JsonNode.Parse(json);
jsonNode["TestData"]["Name"] = "John";

现在这是首选的方式。 - Tomislav Markovski

12

假设有多个属性,你想仅为“TestData”属性添加名称:

using (MemoryStream memoryStream1 = new MemoryStream())
{
    using (Utf8JsonWriter utf8JsonWriter1 = new Utf8JsonWriter(memoryStream1))
    {
        using (JsonDocument jsonDocument = JsonDocument.Parse(json))
        {
            utf8JsonWriter1.WriteStartObject();

            foreach (var element in jsonDocument.RootElement.EnumerateObject())
            {
                if (element.Name == "TestData")
                {
                    utf8JsonWriter1.WritePropertyName(element.Name);

                    // Staring new object
                    utf8JsonWriter1.WriteStartObject();

                    // Adding "Name" property 
                    utf8JsonWriter1.WritePropertyName("Name");
                    utf8JsonWriter1.WriteStringValue("John");

                    // Copying existing values from "TestData" object
                    foreach (var testDataElement in element.Value.EnumerateObject())
                    {
                        testDataElement.WriteTo(utf8JsonWriter1);
                    }

                    utf8JsonWriter1.WriteEndObject();
                }
                else
                {
                    element.WriteTo(utf8JsonWriter1);
                }
            }

            utf8JsonWriter1.WriteEndObject();
        }
    }

    var resultJson = Encoding.UTF8.GetString(memoryStream1.ToArray());
}

在这里,对于每个属性(除了“TestData”属性),我会将整个值按原样写入(通过调用element.WriteTo(utf8JsonWriter1)),对于“TestData”属性,我会开始一个新对象,添加“Name”属性,然后复制每个“TestData”对象的属性。

P.S. 这种方法可行,但我相信一定有更好的解决方案存在。


5
我相信一定存在更好的解决方案。 - user1496062
这有点绕,因为你是从现有的 JSON 对象创建一个新的 JSON 对象。但也许这是我的问题唯一的解决方案,因为 System.Text.Json 库中没有可用于 JSON 对象操作的方法。 - Kunal Patil

4

这里是一个可能的答案

static void Main(string[] args)
    {
        var jsonString = @"
        {
            ""TestData"":{
                ""Year__of__Account"":""2019"",
                ""Tax___x0025_"":""0.06"",
                ""Buildings__1"":""1000"",
                ""Contents__1"":""400"",
                ""Total_Insurable_Value"":""100"",
                ""Buildings__Prem"":""2560.8"",
                ""Contents__Prem"":""1707.2"",
                ""YB__1"":""1950"",
                ""No__Buildings"":""55"",
                ""Location_Sprinklers_YN"":""No"",
                ""test"":""test""
            }
        }
        ";

        var jsonDoc = JsonSerializer.Deserialize<Dictionary<string, object>>(jsonString);

        var testDataDict = JsonSerializer.Deserialize<Dictionary<string, object>>(jsonDoc["TestData"].ToString());

        testDataDict.Add("Name", "John");

        //replace the test data with the modified test data
        jsonDoc["TestData"] = testDataDict;

        Console.WriteLine(JsonSerializer.Serialize(jsonDoc));
    }

4

我刚刚创建了一个 NuGet 包,其中包含一些希望有用的 JsonElement 扩展方法,这些方法允许添加和/或删除属性。它基于使用 Utf8JsonWriter 来根据原始数据创建一个新变异的 JsonElement,就像上面的答案。

GitHub 仓库 | NuGet 包

var jsonString = "{ \"Name\": \"Andrew\", \"EmailAddress\": \"a@b.com\" }";
var jElement = JsonDocument.Parse(jsonString).RootElement;

jElement = jElement.AddProperty("Age", 38)
.AddProperty("Male", true)
.AddProperty("Female", false)
.AddNullProperty("Alien")
.AddProperty("Roles", new string[] { "admin", "user" })
.AddProperty("LastUpdated", DateTime.UtcNow)
.AddProperty("crazyNewObject", new
{
    Name = "Hobbies",
    Value = "bass guitar and writing c# code"
});

希望有人会觉得它们有用,但如果它们不能完全满足你的需求,请进行改进并提交一个拉取请求。

0

使用JsonSerializer反序列化为嵌套字典也是可行的:

static void Main(string[] args)
{
    string testJson = @"
    {
    ""TestData"":{
        ""Year__of__Account"":""2019"",
        ""Tax___x0025_"":""0.06"",
        ""Buildings__1"":""1000"",
        ""Contents__1"":""400"",
        ""Total_Insurable_Value"":""100"",
        ""Buildings__Prem"":""2560.8"",
        ""Contents__Prem"":""1707.2"",
        ""YB__1"":""1950"",
        ""No__Buildings"":""55"",
        ""Location_Sprinklers_YN"":""No"",
        ""test"":""test""
        }
    }";

    using (var memoryStream1 = new MemoryStream())
    {
        using (var utf8JsonWriter1 = new Utf8JsonWriter(memoryStream1))
        {
            //For each level in json tree an additional dictionary must be added
            var jsonDict = JsonSerializer.Deserialize<Dictionary<string, Dictionary<string, object>>>(testJson);
            jsonDict["TestData"].Add("Name", "John");
            JsonSerializer.Serialize<object>(utf8JsonWriter1, jsonDict);
        }

        string testString = Encoding.UTF8.GetString(memoryStream1.ToArray());
    }
}

但请注意,新属性始终添加到TestData块的末尾。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接