如何忽略生成的JSON中的空对象文字? [英] How to ignore empty object literals in the produced JSON?

查看:39
本文介绍了如何忽略生成的JSON中的空对象文字?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用Json.NET将复杂的C#对象图转换为JSON。由于忽略对象中具有默认值的属性,我通常会在输出中得到空的对象文字,我希望将其省略。

例如:

public class Sample {
  public int Value { get; set; }
  public string Name { get; set; }
}

public class ParentSample {
  // this property should never be null, hence the initializer
  public Sample Sample { get; } = new Sample();
}

..

var obj = new ParentSample();
// settings for indentation and excluding default values omitted for clarity
var output = JsonConvert.SerializeObject(obj, ... );
// output will be 
// {
//   Sample: {}
// }
//
// I'd like it to be 
// {}

我知道一些特定于类型的解决方案,比如向ParentSample类型添加ShouldSerializeSample布尔方法,并检查是否所有属性都是默认的。但是,我想要一个通用的解决方案,例如,自定义合同解析器。

推荐答案

在注释中,您似乎已经决定使用正则表达式来清除空对象。这个想法的一个问题是,它可能不能处理我称之为"递归空对象"的情况。换句话说,大概是这样的:

{
    "foo":
    {
        "bar": {},
        "baz": {}
    }
}

如果您使用Regex成功删除了最深层的空对象barbaz(同时还意识到需要删除它们之间的逗号以保持JSON有效),则仍将留下一个空对象:foo

{
    "foo":
    {
    }
}
我认为更好的解决方案是将数据加载到JToken层次结构中,然后在将其写出到JSON之前使用递归方法删除所有空子对象。这样的功能应该可以满足您的需求:

using System;
using Newtonsoft.Json.Linq;

public static class JsonHelper
{
    public static string SerializeToMinimalJson(object obj)
    {
        return JToken.FromObject(obj).RemoveEmptyChildren().ToString();
    }

    public static JToken RemoveEmptyChildren(this 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 = child.RemoveEmptyChildren();
                }
                if (!child.IsEmptyOrDefault())
                {
                    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 = child.RemoveEmptyChildren();
                }
                if (!child.IsEmptyOrDefault())
                {
                    copy.Add(child);
                }
            }
            return copy;
        }
        return token;
    }

    public static bool IsEmptyOrDefault(this JToken token)
    {
        return (token.Type == JTokenType.Array && !token.HasValues) ||
               (token.Type == JTokenType.Object && !token.HasValues) ||
               (token.Type == JTokenType.String && token.ToString() == String.Empty) ||
               (token.Type == JTokenType.Boolean && token.Value<bool>() == false) ||
               (token.Type == JTokenType.Integer && token.Value<int>() == 0) ||
               (token.Type == JTokenType.Float && token.Value<double>() == 0.0) || 
               (token.Type == JTokenType.Null);
    }

}

然后可以按如下方式序列化对象:

var json = JsonHelper.SerializeToMinimalJson(obj);

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

编辑

如果您想使用此方法来支持[DefaultValue]属性,您可以通过修改SerializeToMinimalJson()方法来创建JsonSerializer的实例,在其上设置DefaultValueHandling属性,然后将其传递给JToken.FromObject(),如下所示。(必须以这种方式完成,因为JTokens没有对使用FromObject()创建它们的原始对象的引用,因此无法在此之后获取[DefaultValue]属性的值。)

public static string SerializeToMinimalJson(object obj)
{
    var serializer = new JsonSerializer();
    serializer.NullValueHandling = NullValueHandling.Ignore;
    serializer.DefaultValueHandling = DefaultValueHandling.Ignore;
    return JToken.FromObject(obj, serializer).RemoveEmptyChildren().ToString();
}
如果这样做,您可能还希望更改IsEmptyOrDefault()方法,以便它不会删除"默认"的值。您可以将其简化为:

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

小提琴:https://dotnetfiddle.net/0yVRI5

这篇关于如何忽略生成的JSON中的空对象文字?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆