【问题标题】:Update specific value in JSON file更新 JSON 文件中的特定值
【发布时间】:2021-08-14 23:32:30
【问题描述】:

我正在寻找一种通过名称查找特定 json 值并将其值设置为 null 的方法。 json文件的构造可以是任何东西,并不总是一样的。

假设 json 看起来像这样:

[
{
    "id": "1111",
    "email": "email@email.com",
},
{
    "id": "2222",
    "email": "email2@email2.com",
}]

我要找的结果是这样的:

[
{
    "id": "1111",
    "email": null,
},
{
    "id": "2222",
    "email": null,
}]

当对象更复杂时,它也应该可以工作。

{
"reservations": [
    {
        "id": "111",
        "bookingId": "",
        "status": "",
        "checkInTime": "",
        "checkOutTime": "",
        "property": {
            "id": "",
            "code": "",
            "name": "",
        },
        "primaryGuest": {
            "firstName": "",
            "middleInitial": "",
            "lastName": "",
            "email": "email@email.com",
            "phone": "",
            "address": {
                "addressLine1": "",
                "postalCode": "",
                "city": "",
                "countryCode": ""
            }
        },
        "booker": {
            "firstName": "",
            "middleInitial": "",
            "lastName": "",
            "email": "email2@email.com",
            "phone": ""
        }
   }]}

我尝试过使用 JArray、JObject 类等,但它只在propety["email"] 是第一个孩子而不是更深的情况下才有效。不知道如何做到这一点。

 private JObject HashSensitiveData(JContainer jContainer)
    {
        if (!jContainer.Descendants().Any())
        {
            return null;
        }

        var objects = jContainer.Descendants().OfType<JObject>();

        foreach (var property in objects)
        {
            foreach (var emailProperty in property.Properties().Where(x => x.Name.CaseInsensitiveContains(LoggerHashedProperties.Email.ToString())))
            {
                var email = emailProperty.Value.ToString();
                property[emailProperty.Name] =null
            }
        }

        return HashSensitiveData(jContainer);
    }

【问题讨论】:

  • "json 文件的构造可以是任何东西,它并不总是一样的。"连结构都不知道怎么用?请贴出真实代码
  • 结构不是恒定的,这意味着电子邮件节点可以嵌套。我正在使用它进行日志记录 - 我将收到的 api 请求响应记录为 json,并且需要将节点电子邮件的所有值设置为 null。

标签: c# json .net linq


【解决方案1】:

使用NewtonSoft,我曾经做过一个flatten函数来分析任意深度的json文件:

IEnumerable<JProperty> Flatten(JToken token)
{
    return token.Children<JProperty>().Concat(
        token.Children().SelectMany(t => Flatten(t)))
        .Where(t => t.Value is JValue);
}

它返回文件中所有“端点”JsonPropertys 的平面列表(例如:所有 "xyx" : primitive value 条目)。使用它,您可以简单地反序列化您的 Json,找到所有“电子邮件”属性并将其值设置为 null

var jobj = JsonConvert.DeserializeObject<JObject>(getJson());

var flattened = Flatten(jobj);

foreach (var jprop in flattened.Where(t => t.Name == "email"))
{
    jprop.Value = null;
}
var json = JsonConvert.SerializeObject(jobj).Dump();

“更复杂”的 json 的结果(添加了一封更深入的电子邮件以使其更有趣):

{
  "reservations": [
    {
      "id": "111",
      "bookingId": "",
      "status": "",
      "checkInTime": "",
      "checkOutTime": "",
      "property": {
        "id": "",
        "code": "",
        "name": ""
      },
      "primaryGuest": {
        "firstName": "",
        "middleInitial": "",
        "lastName": "",
        "email": null,
        "phone": "",
        "address": {
          "email": null,
          "addressLine1": "",
          "postalCode": "",
          "city": "",
          "countryCode": ""
        }
      },
      "booker": {
        "firstName": "",
        "middleInitial": "",
        "lastName": "",
        "email": null,
        "phone": ""
      }
    }
  ]
}

【讨论】:

  • 正是我想要的,谢谢。
【解决方案2】:

使用 System.Text.Json 和 Utf8JsonWriter,您可以递归地处理和编写 JSON:

public static void RemoveContent(JsonElement element, Utf8JsonWriter writer)
{
    // Current element is an array, so we have to iterate over all elements.
    if (element.ValueKind == JsonValueKind.Array)
    {
        writer.WriteStartArray();
        foreach (var e in element.EnumerateArray())
        {
            RemoveContent(e, writer);
        }
        writer.WriteEndArray();
    }
    // Current element is an object, so we have to process all properties.
    else if (element.ValueKind == JsonValueKind.Object)
    {
        writer.WriteStartObject();
        foreach (var e in element.EnumerateObject())
        {
            writer.WritePropertyName(e.Name);

            // * Process specific elements. ************************************************
            if (e.Name == "email") { writer.WriteNullValue(); }
            else RemoveContent(e.Value, writer);
        }
        writer.WriteEndObject();
    }
    // We are at the leaf (a string property, ...) and we write this as it is.
    else
    {
        element.WriteTo(writer);
    }
}

用法:

using var stream = new MemoryStream();
// We have to flush writer before reading it's content.
using (var writer = new Utf8JsonWriter(stream, new JsonWriterOptions { SkipValidation = true }))
{
    var element = JsonDocument.Parse(jsonStr).RootElement;
    RemoveContent(element, writer);
}
// Stream contains a byte array with UTF-8 content.
// If you want a string, you can use UTF8 decoding.
var json = System.Text.Encoding.UTF8.GetString(stream.ToArray());
Console.WriteLine(json);

【讨论】:

  • 有趣的解决方案。我想知道它是否对资源的要求较低,所以也许是非常大的 JSON 文件的解决方案。
猜你喜欢
  • 2021-10-28
  • 2020-07-11
  • 1970-01-01
  • 1970-01-01
  • 2020-07-21
  • 1970-01-01
  • 2020-01-02
  • 1970-01-01
  • 2021-08-17
相关资源
最近更新 更多