如何根据字段描述的对象类型根据 JSON 模式验证 JSON 对象?

2023-12-30

我有许多对象(消息)需要根据 JSON 模式(draft-04)进行验证。每个对象都保证有一个“type”字段,用于描述其类型,但每种类型都有一组完全不同的其他字段,因此每种类型的对象都需要一个唯一的模式。

我看到了几种可能性,但没有一种特别有吸引力,但我希望我错过了一些东西。

可能性 1:对每种消息类型使用 oneOf。我想这会起作用,但问题是很长的验证错误,以防出现问题:验证器倾向于报告失败的每个模式,其中包括“oneOf”数组中的所有元素。

{
  "oneOf":
  [
    {
      "type": "object",
      "properties":
      {
        "t":
        {
          "type": "string",
          "enum":
          [
            "message_type_1"
          ]
        }
      }
    },
    {
      "type": "object",
      "properties":
      {
        "t":
        {
          "type": "string",
          "enum":
          [
            "message_type_2"
          ]
        },
        "some_other_property":
        {
          "type": "integer"
        }
      },
      "required":
      [
        "some_other_property"
      ]
    }
  ]
}

可能性 2:嵌套的“if”、“then”、“else”三元组。我还没有尝试过,但我想在这种情况下错误可能会更好。不过写起来很麻烦,嵌套的if堆积起来。

可能性 3:对于每个可能的“t”值都有一个单独的方案。这是最简单的解决方案,但我不喜欢它,因为它阻止我在模式中使用公共元素(通过引用)。

那么,这些是我唯一的选择,还是我可以做得更好?


由于“type”是 JSON 架构关键字,为了清楚起见,我将按照您的指导并使用“t”作为类型区分字段。

没有特定的关键字来完成或指示这一点(但是,请参阅https://github.com/json-schema-org/json-schema-spec/issues/31 https://github.com/json-schema-org/json-schema-spec/issues/31供讨论)。这是因为,为了验证的目的,您需要做的一切都已经是可能的。在 JSON 模式中,错误是次要的验证。我们要做的就是限制我们看到的错误数量,因为很明显,到了某个点,错误就不再有效。

通常,当您验证消息时,您首先知道其类型,然后阅读消息的其余部分。例如,在 HTTP 中,如果您正在阅读以以下开头的行Date:并且下一个字符不是数字或字母,您可以立即发出错误(例如“意外的波浪号,预期月份名称”)。

但在 JSON 中,情况并非如此,因为属性是无序的,并且您可能直到最后才遇到“t”(如果有的话)。 “如果/那么”可以帮助解决这个问题。

但首先,首先要找出最重要的限制因素,并将它们移到顶部。

首先,使用"type": "object" and "required":["t"]在您的顶级架构中,因为在所有情况下都是如此。

其次,使用“properties”和“enum”枚举其所有有效值。这样,如果“t”确实输入错误,它将是顶级架构中的错误,而不是子架构中的错误。

如果所有这些约束都通过,但文档仍然无效,那么更容易断定问题一定是消息的其他内容,而不是“t”属性本身。

现在在每个子模式中,使用"const"将子模式与类型名称相匹配。

我们得到这样的模式:

{
  "type": "object",
  "required": ["t"],
  "properties": { "t": { "enum": ["message_type_1", "message_type_2"] } }
  "oneOf": [
     {
        "type": "object",
        "properties": {
          "t": { "const": "message_type_1" }
        }
     },
     {
        "type": "object",
        "properties": 
          "t": { "const": "message_type_2" },
          "some_other_property": {
             "type": "integer"
          }
        },
        "required": [ "some_other_property" ]
     }
  ]
}

现在,将每种类型拆分为不同的架构文件。通过以“t”命名该文件,使其可供人类访问。这样,应用程序可以读取对象流并选择模式来验证每个对象。

{
  "type": "object",
  "required": ["t"],
  "properties": { "t": { "enum": ["message_type_1", "message_type_2"] } }
  "oneOf": [
     {"$ref": "message_type_1.json"},
     {"$ref": "message_type_2.json"}
  ]
}

理论上,验证器现在拥有足够的信息来产生更清晰的错误(尽管我不知道有任何验证器可以做到这一点)。

因此,如果这不能为您生成足够干净的错误报告,您有两个选择:

首先,您可以自己实现部分验证过程。如上所述,使用流式 JSON 解析器,例如Oboe.js http://www.oboejs.com/要读取流中的每个对象,解析该对象并读取“t”属性,然后应用适当的架构。

或者其次,如果您确实想纯粹在 JSON Schema 中执行此操作,请在“allOf”内使用“if/then”语句:

{
  "type": "object",
  "required": ["t"],
  "properties": { "t": { "enum": ["message_type_1", "message_type_2"] } }
  "allOf": [
     {"if":{"properties":{"t":{"const":"message_type_1"}}}, "then":{"$ref": "message_type_1.json"}},
     {"if":{"properties":{"t":{"const":"message_type_2"}}}, "then":{"$ref": "message_type_2.json"}}
  ]
}

这应该会产生以下错误:

t不是“message_type_1”或“message_type_2”之一

or

(因为t=“消息_类型_2”)some_other_property不是整数

但两者都不是。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何根据字段描述的对象类型根据 JSON 模式验证 JSON 对象? 的相关文章

随机推荐

  • For 循环正在跳过一些东西! Python

    我正在尝试运行此代码 以便它为列表的所有元素运行一个函数 出于说明目的 基本上应该打印 Possible Word possible word 对于我的列表中的所有项目 因此 如果我输入 p r s 它将运行打印 3 次 每一项打印一次 我
  • 在生产中调试反应应用程序时无法在控制台中看到我的变量

    我是反应世界的新手 并尝试在我的共享点环境中使用它 我正在使用源映射打包用于生产的应用程序 并将其上传到我将在其中使用它的共享点站点 应用程序在共享点中运行没有问题 但在开发人员工具箱中我无法完全调试它 我可以看到我的 js 文件 放置调试
  • 从 NSDate 获取时间返回 nil

    我试图在图表上显示时间 并且我有一个完整的时间戳 格式为 2012 08 28 18 50 24 当我尝试从该日期获取时间时 它在 NSDate 中返回 nil NSDateFormatter formatter NSDateFormatt
  • 使用 glvertex4i 传递网格面索引时顶点着色器错误

    初始化 GL List 进行处理 glBegin GL POINTS for i 0 i lt faceNum i mesh gt GetFaceNodes i 1 ver 0 ver 1 ver 2 ver 3 glVertex4i ve
  • 帧指针省略?有风险吗?

    我总是在编译器中打开此功能 它在阅读更干净的汇编代码时对调试有很大帮助 我认为它对速度优化方面没有太大影响 使CPU能够进行流水线操作 但至少它确实为寄存器分配提供了新的机会 因此获得了一个新的空闲寄存器EBP 不确定编译器是否会使用它 我
  • EJB 容器中的 ThreadLocal(和 Singleton)

    我编写了一个授权系统 它依赖于代表当前用户的对象 为了简化编程并提高性能 我想在用户登录后将这些对象保存在 ThreadLocal 中 它看起来像这样 public class UserCache private static final
  • C# Diamond-继承(接口实现)

    如果一个类从两个单独的接口实现一个接口 它的行为是否与仅实现一次相同 Example public interface IAnimal public interface IFullAnimal IAnimal public interfac
  • 将枚举值添加到简单的组合框

    我有一个关于 C 和 WPF 的非常简单的问题要问 在我的这次尝试之后 我的问题将随之而来 private void Window Loaded object sender RoutedEventArgs e foreach var ite
  • gdb 上漂亮的打印 boost::unordered_map

    最近我开始在我的系统上使用优秀的 boost unordered map 但有一个缺点 我不知道如何检查其内容 在 gdb 上打印它会给我一个 table 和一个 buckets 但还没有找到这些项目在哪里 有人对此有任何线索吗 对于那些想
  • 将Java线程类放入一个单独的类中

    考虑以下 SWT 代码示例 http dev eclipse org viewcvs index cgi org eclipse swt snippets src org eclipse swt snippets Snippet151 ja
  • Microsoft SQL Server 分析服务 OLAP 多维数据集

    我试图找到一种工具来提高应用程序报告的性能 我听说了 OLAP Reporting Services 它被描述为完成这项工作的绝佳组合 无论如何 我没有找到使 OLAP 多维数据集保持最新的方法 因为原始数据库中的数据可能会更改 这是一个交
  • 为什么代码终止时出现“未找到解决方案”错误和“退出:收敛到局部不可行点。问题可能不可行”?

    我似乎不明白为什么IPOPT无法找到解决方案 最初 我认为这个问题完全不可行 但是当我减少总列数至以下任意号码161000 or 注释掉最后一个约束方程其中包含总列数 它解决并退出Optimal Solution Found and a f
  • Matplotlib:如何再次显示绘图?

    假设我做了一个情节Ipython Notebook 在几个单元格之后 我想再次渲染它 这样我就可以将它与其他图进行比较 我该怎么做 a 1 2 3 4 b 3 4 5 6 fig plt plot a b color black 这将显示情
  • Twig 迭代对象属性

    我在 Twig 文档中读到 可以通过以下方式迭代关联数组 for key value in array key value endfor 我想知道这对于 stdClass 类型的对象是否也可能 我希望 Twig 能够以属性名称作为键来迭代对
  • 我可以在 ASP.NET 中使用 X509Certificate2 而不使用证书存储吗?

    我正在尝试在 Rackspace 云中的 ASP NET Web 服务中使用 X509Certificate 我有一种感觉 存储在云节点上的证书可能会引起问题 我也有一个与此相关的问题 但我收到的问题是使用 iPhone Apple 推送通
  • Twitter Bootstrap 模态宽度问题

    我的应用程序具有许多模式 所有模式都有不同的宽度 我知道您可以通过执行以下操作来设置模态内联的宽度 宽度 400 像素 左边距 200px 这效果很好 但是如果你压缩窗口 它会将模态占到屏幕的 50 所以你看不到一半的模态渲染 在这些小分辨
  • 如何将一个数据框按行拆分成多个数据框然后导出到excel?右

    这是我正在使用的数据 Sales lt data frame State c New York New Jersey Texas New Mexico California Kansas Florida Alaska Montana Mai
  • 如何在 JFrame 中启动命令行 Java 代码?

    我有一个通过基本命令行界面执行的Java 程序 我想知道是否将其放入窗口 JFrame 中 是否可以 我能怎么做 谢谢 如果你想在 jFrame 中使用命令行 我认为这不是一个好主意 如果JFrame启动了 说明程序已经启动了 您必须使用命
  • 设置javascript对象多级属性的简单方法?

    我正在尝试创建一个像这样的javascript对象 var allUserExpiry allUserExpiry aData userId aData courseId aData uscId aData 但我收到了类似的错误allUse
  • 如何根据字段描述的对象类型根据 JSON 模式验证 JSON 对象?

    我有许多对象 消息 需要根据 JSON 模式 draft 04 进行验证 每个对象都保证有一个 type 字段 用于描述其类型 但每种类型都有一组完全不同的其他字段 因此每种类型的对象都需要一个唯一的模式 我看到了几种可能性 但没有一种特别