【问题标题】:How to Check if Json object has all values filled如何检查 Json 对象是否已填充所有值
【发布时间】:2017-10-20 17:45:23
【问题描述】:

我从外部 api 获得一个大的嵌套 json 对象。我想确保所有字段都填充在该 json 对象中。有没有可用的库来做到这一点? Newtonsoft.JsonJToken 类,它检查 Json 的模式是否有效,但我没有找到任何方法来检查 json 对象内的所有字段是否都已填充。

场景:我正在构建一个 api,用于收集有关个人或实体的信息。有许多信息来源。我需要继续搜索数据,直到所需的对象已满。所以首先调用 api1,获取一些数据,检查对象是否已满。如果对象未满,则转到 api2 等等。所以调用在对象满后返回。 一个关键点是所需的对象架构不是静态的。

我可以将其反序列化为 POCO 并循环遍历每个嵌套对象,但我正在寻找更好的解决方案。

非常感谢任何建议。

【问题讨论】:

  • 您可以使用来自Json.NET require all properties on deserializationRequireObjectPropertiesContractResolver。从你的问题中不清楚你是否想要Required.Always or Required.AllowNull
  • 我需要Required.Always。所以它在反序列化时检查?它也适用于儿童吗?
  • 在不反序列化 json 的情况下是否有同样的结果?
  • 所以它在反序列化时进行检查? 是的。 它也适用于儿童吗? 是的。使用自定义合约解析器的优点是它适用于所有被反序列化的类型,无需手动向这些类型添加属性。 在不反序列化 json 的情况下是否可以实现相同的结果? Json.NET 通过查看被反序列化类型的协定来确定预期属性集。您还想如何指定一组必需的属性?还是您只是希望所有 JSON 属性都不为空?
  • 是的,我希望对象内的所有 json 属性都不为空。我正在开发一个从其他 api 获取信息的 api。它一直在寻找下一个 api,直到它获得所需的所有信息。所以我需要每次检查对象是否已满并继续下一个 api,如果对象已满则返回。

标签: c# json json.net json-deserialization


【解决方案1】:

如果您有一个 JSON 字符串,并且只是想检查任何属性值或数组项是否为 null,您可以解析为 JToken,使用 JContainer.DescendantsAndSelf() 递归下降 JToken 层次结构,并检查每个JValuenull 使用以下扩展方法:

public static partial class JsonExtensions
{
    public static bool AnyNull(this JToken rootNode)
    {
        if (rootNode == null)
            return true;
        // You might consider using some of the other checks from JsonExtensions.IsNullOrEmpty()
        // from https://stackoverflow.com/questions/24066400/checking-for-empty-null-jtoken-in-a-jobject
        return rootNode.DescendantsAndSelf()
            .OfType<JValue>()
            .Any(n => n.Type == JTokenType.Null);
    }

    public static IEnumerable<JToken> DescendantsAndSelf(this JToken rootNode)
    {
        if (rootNode == null)
            return Enumerable.Empty<JToken>();
        var container = rootNode as JContainer;
        if (container != null)
            return container.DescendantsAndSelf();
        else
            return new[] { rootNode };
    }
}

然后做:

var root = JToken.Parse(jsonString);
var anyNull = root.AnyNull();

如果你只想检查空属性值(即数组中的空值是可以的)你可以使用以下扩展方法:

public static partial class JsonExtensions
{
    public static bool AnyNullPropertyValues(this JToken rootNode)
    {
        if (rootNode == null)
            return true;
        return rootNode.DescendantsAndSelf()
            .OfType<JProperty>()
            .Any(p => p.Value == null || p.Value.Type == JTokenType.Null);
    }
}

(从您的问题中并不能完全清楚您想要哪个。)

示例.Net fiddle

【讨论】:

    【解决方案2】:

    如果我理解正确,您有一些复杂的 JSON 对象,具有一组必需和非必需的属性。

    我在这里看到三个解决方案:

    1. 您已经提到过 JSON 模式验证。这是其中一种实现:Json.NET Schema
    2. 创建一个 POCO 对象并使用相应的必需/非必需属性标记所有属性。在这种情况下,如果 json-string 不包含任何强制性数据,您将遇到异常。比如Json.NET's JsonPropertyAttribute是怎么做的:

      [JsonObject]
      public class PocoObject
      {
          [JsonProperty("$schema", Required = Required.Default, NullValueHandling = NullValueHandling.Ignore)]
          public string Schema { get; set; }
      
          [JsonProperty("name", Required = Required.Always)]
          public string Name { get; set; }
      
          [JsonProperty("properties", Required = Required.Always)]
          public MorePropertiesObject Properties { get; set; }
      }
      

      作为奖励,您可以添加自定义属性、方法、转换器等

    3. 将原始 json 反序列化为类似字典的结构,并使用您自己的手写验证器对其进行验证。比如:

      try
      {
          var jo = JObject.Parse(jsonString);
          Contract.Assert(!string.IsNullOrEmpty(jo["root"]["prop1"].ToString()));
          Contract.Assert(!string.IsNullOrEmpty(jo["root"]["prop2"].ToString()));
      }
      catch (JsonReaderException) { }
      catch (JsonSerializationException) { }
      

    提供的代码示例供您提及Newtonsoft.Json

    【讨论】:

    • 感谢 Ihor。但是响应 json 对象不是静态的。它会有所不同,并且该对象内的所有属性都是必需的。因此,如果我传递一个随机的 json 对象,如果所有属性都已填充,它应该返回我。
    • @Venky,dbc 提出了我的第三个变体的增强版本,它应该适合您的问题。请记住,如果您还需要验证空数组,则必须在 AnyNull() 方法中再添加一项检查(Json.net 中的数组以 JArray 对象表示。
    猜你喜欢
    • 2020-07-27
    • 2014-11-28
    • 2018-01-29
    • 1970-01-01
    • 2020-01-16
    • 1970-01-01
    • 2011-05-16
    • 1970-01-01
    相关资源
    最近更新 更多