JSON.NET 序列化 JObject 而忽略空属性

时间:2023-04-24
本文介绍了JSON.NET 序列化 JObject 而忽略空属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

问题描述

我有一个 JObject 用作调用 RESTful Web 服务的 模板.这个 JObject 是通过解析器创建的,因为它被用作模板告诉用户端点模式是什么样的,我必须想办法保留所有属性,这就是我默认的原因将它们的值设置为 null.例如,这是对象最初的样子:

I have a JObject which is used as a template for calling RESTful web services. This JObject gets created via a parser and since it's used as a template telling the user what the endpoint schema looks like, I had to figure out a way to preserve all properties, which is why I'm defaulting their values to null. As as example, this is what the object originally looks like:

{  
   "Foo":{  
      "P1":null,
      "P2":null,
      "P3":null,
      "P4":{  
         "P1":null,
         "P2":null,
         "P3":null,
      },
      "FooArray":[  
         {  
            "F1":null,
            "F2":null,
            "F3":null,
         }
      ]
   },
   "Bar":null
}

然后用户可以根据需要填写各个字段,例如 Foo.P2Foo.P4.P1:

The user is then able to fill in individual fields as they need, such as Foo.P2 and Foo.P4.P1:

{  
   "Foo":{  
      "P1":null,
      "P2":"hello world",
      "P3":null,
      "P4":{  
         "P1":1,
         "P2":null,
         "P3":null,
      },
      "FooArray":[  
         {  
            "F1":null,
            "F2":null,
            "F3":null,
         }
      ]
   },
   "Bar":null
}

意味着他们只关心这两个领域.现在我想将此模板 (JObject) 序列化回 JSON 字符串,但只希望显示那些已填充的字段.所以我尝试了这个:

meaning they only care about those two fields. Now I want to serialize this template (JObject) back to a JSON string, but want only those fields that are populated to show up. So I tried this:

string json = JsonConvert.SerializeObject(template,
    new JsonSerializerSettings
    {
        NullValueHandling = NullValueHandling.Ignore
    });

很遗憾,这不起作用.我遇到了 这个问题 并意识到对象中的 null 值是实际的 JToken 类型,而不是真正的 null,这是有道理的.但是,在这种非常特殊的情况下,我需要能够摆脱这些未使用"的字段.我尝试手动迭代节点并删除它们,但这也不起作用.请注意,我使用的唯一托管类型是 JObject;我没有将对象转换为或定义属性的模型,因为此模板"在运行时被解析.我只是想知道是否有人遇到过这样的问题并有任何见解.非常感谢任何帮助!

Unfortunately, this didn't work. I came across this question and realized that a null value in the object is an actual JToken type and not really a null, which makes sense. However, in this very particular case, I need to be able to get rid of these "unused" fields. I tried manually iterating over nodes and removing them but that didn't work either. Note that the only managed type I'm using is JObject; I don't have a model to convert the object to or define attributes on, since this "template" gets resolved at runtime. I was just wondering if anyone has encountered a problem like this and has any insights. Any help is greatly appreciated!

推荐答案

您可以使用如下递归辅助方法从 JToken 中删除 null 值序列化之前的层次结构.

You can use a recursive helper method like the one below to remove the null values from your JToken hierarchy prior to serializing it.

using System;
using Newtonsoft.Json.Linq;

public static class JsonHelper
{
    public static JToken RemoveEmptyChildren(JToken token)
    {
        if (token.Type == JTokenType.Object)
        {
            JObject copy = new JObject();
            foreach (JProperty prop in token.Children<JProperty>())
            {
                JToken child = prop.Value;
                if (child.HasValues)
                {
                    child = RemoveEmptyChildren(child);
                }
                if (!IsEmpty(child))
                {
                    copy.Add(prop.Name, child);
                }
            }
            return copy;
        }
        else if (token.Type == JTokenType.Array)
        {
            JArray copy = new JArray();
            foreach (JToken item in token.Children())
            {
                JToken child = item;
                if (child.HasValues)
                {
                    child = RemoveEmptyChildren(child);
                }
                if (!IsEmpty(child))
                {
                    copy.Add(child);
                }
            }
            return copy;
        }
        return token;
    }

    public static bool IsEmpty(JToken token)
    {
        return (token.Type == JTokenType.Null);
    }
}

演示:

string json = @"
{
    ""Foo"": {
        ""P1"": null,
        ""P2"": ""hello world"",
        ""P3"": null,
        ""P4"": {
            ""P1"": 1,
            ""P2"": null,
            ""P3"": null
        },
        ""FooArray"": [
            {
                ""F1"": null,
                ""F2"": null,
                ""F3"": null
            }
        ]
    },
    ""Bar"": null
}";

JToken token = JsonHelper.RemoveEmptyChildren(JToken.Parse(json));
Console.WriteLine(token.ToString(Formatting.Indented));

输出:

{
  "Foo": {
    "P2": "hello world",
    "P4": {
      "P1": 1
    },
    "FooArray": [
      {}
    ]
  }
}

小提琴:https://dotnetfiddle.net/wzEOie

请注意,在删除所有空值之后,您将在 FooArray 中有一个空对象,这可能是您不想要的.(如果那个对象被移除了,那么你会得到一个空的 FooArray,你也可能不想要它.)如果你想让帮助方法在移除时更积极,你可以改变IsEmpty 函数到此:

Notice that, after removing all null values, you will have an empty object in the FooArray, which you may not want. (And if that object were removed, then you'd have an empty FooArray, which you also may not want.) If you want to make the helper method more aggressive in its removal, you can change the IsEmpty function to this:

    public static bool IsEmpty(JToken token)
    {
        return (token.Type == JTokenType.Null) ||
               (token.Type == JTokenType.Array && !token.HasValues) ||
               (token.Type == JTokenType.Object && !token.HasValues);
    }

进行该更改后,您的输出将如下所示:

With that change in place, your output would look like this instead:

{
  "Foo": {
    "P2": "hello world",
    "P4": {
      "P1": 1
    }
  }
}

小提琴:https://dotnetfiddle.net/ZdYogJ

这篇关于JSON.NET 序列化 JObject 而忽略空属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

上一篇:如何创建 JSON.NET 日期到字符串自定义转换器 下一篇:事先不知道密钥的情况下,如何在 C# 中解析 JSON 对象?

相关文章