You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JsonSchema.Net可空属性验证误报的排查与过滤咨询

问题描述

我正在使用JsonSchema.Net验证JSON文档与预设Schema的一致性。部分属性在Schema中通过oneOf关键字定义为可空类型(格式如{"oneOf":[{"type":"string"},{"type":"null"}]})。但验证时,这些可空属性的部分评估结果会返回IsValid=false,错误信息与实际JSON值相悖(例如“值为"null",但应为"integer"”或“值为"number",但应为"null"”)。我想知道问题原因,以及如何过滤此类误报,以便快速定位真正的错误节点。

文档示例

{
  "referenceNumber": "35366",
  "storageZone": null,
  "maxCount": null,
  "length":  124.5
}

对应的JSON Schema

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Schema Example",
  "$defs": {
    "stringNullable": {
      "oneOf": [
        { "type": "string" },
        { "type": "null" }
      ]
    },
    "integerNullable": {
      "oneOf": [
        { "type": "integer" },
        { "type": "null" }
      ]
    },
    "numberNullable": {
      "oneOf": [
        { "type": "number" },
        { "type": "null" }
      ]
    }
  },
  "type": "object",
  "properties": {
    "referenceNumber": {
      "type": "string"
    },
    "storageZone": {
      "$ref": "#/$defs/stringNullable"
    },
    "maxCount": {
      "$ref": "#/$defs/integerNullable"
    },
    "length": {
      "$ref": "#/$defs/numberNullable"
    }
  }
}

代码示例

[Test]
public void JsonSchemaAsserts()
{
    var schema = JsonSchema.FromFile("./SchemaExample.json");
    var jsonText = File.ReadAllText("./DataExample.json");
    var json = JsonNode.Parse(jsonText);

    var validationResult = schema.Evaluate(json, new EvaluationOptions() { OutputFormat = OutputFormat.List });

    Assert.That(validationResult.IsValid, Is.True);

    var validationErrors = validationResult.Details.Where(d => !d.IsValid && d.HasErrors).ToList();

    Assert.That(validationResult, Is.Empty);
}
问题原因

这是oneOf关键字的特性导致的——oneOf要求恰好有一个子Schema验证通过。验证可空属性时,JsonSchema.Net会对oneOf下的每个子Schema分别评估,每个子Schema的失败结果都会被记录到Details集合中,但最终整个oneOf的验证结果是通过的(因为有一个子Schema匹配成功)。你看到的“误报”其实是单个子Schema的失败信息,而非整个属性的最终验证结果。

比如maxCount为null时,integer类型的子Schema验证失败,会生成错误信息,但null类型的子Schema验证通过,所以整个oneOf的结果是有效的,只是Details里包含了子Schema的失败记录。

解决方法

1. 修正错误过滤逻辑

要过滤掉这些子Schema的失败信息,只保留真正的错误,需要判断错误是否来自最终验证失败的节点。修改代码中的错误筛选逻辑,只保留那些自身验证失败且父节点也验证失败的错误:

[Test]
public void JsonSchemaAsserts()
{
    var schema = JsonSchema.FromFile("./SchemaExample.json");
    var jsonText = File.ReadAllText("./DataExample.json");
    var json = JsonNode.Parse(jsonText);

    var validationResult = schema.Evaluate(json, new EvaluationOptions() { OutputFormat = OutputFormat.List });

    Assert.That(validationResult.IsValid, Is.True);

    // 过滤仅保留真正的错误节点:自身验证失败,且父节点也未通过验证
    var validationErrors = validationResult.Details
        .Where(d => !d.IsValid && d.HasErrors 
                    && (d.Parent == null || !d.Parent.IsValid))
        .ToList();

    Assert.That(validationErrors, Is.Empty);
}

2. 使用简化的可空类型定义(推荐)

从JSON Schema Draft 2019-09开始,支持直接通过type数组定义可空类型,无需使用oneOf。这种方式的验证不会产生子节点的失败记录,结果更简洁:

修改Schema中的可空定义:

"$defs": {
  "stringNullable": {
    "type": ["string", "null"]
  },
  "integerNullable": {
    "type": ["integer", "null"]
  },
  "numberNullable": {
    "type": ["number", "null"]
  }
}

这样修改后,Details集合中只会保留真正的验证失败信息,无需额外过滤。

内容的提问来源于stack exchange,提问作者GKalnytskyi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 19:45:27