Json 面向方面的架构 Json 文件

Json Schema for Aspect Oriented Json files

所以我的 json 结构是面向方面的,这意味着 json 是一种结构,每个数据都由一个键表示,该键将定义其内容的结构。

例如:

[
  {
    "nv": [{ "ln": 123 }]
  },

  {
    "metadata": [{ "name": "nodes" }, { "name": "edges" }]
  },
  {
    "nodes": [{ "@id": 1 }, { "@id": 2 }]
  },
  {
    "edges": [
      { "@id": 1, "nodeId": 1 },
      { "@id": 2, "nodeId": 2 }
    ]
  },
  {
    "status": [{ "success": true }]
  }
]

如图所示,有 3 个对象(nv、元数据、状态),根据元数据中的 name,json 文件中会有对象。

我试过这样的事情:

{
  "type": "array",
  "items": [
    {
      "type": "object",
      "properties": {
        "nv": { "type": "array", "items": { "$ref": "#definitions/nv" } }
      },
      "required": ["nv"]
    },
    {
      "type": "object",
      "properties": {
        "metaData": {
          "type": "array",
          "items": { "$ref": "#definitions/metadata" }
        }
      },
      "required": ["metaData"]
    },
    {
      "anyOf": [
        {
          "type": "object",
          "properties": {
            "nodes": {
              "type": "array",
              "items": { "$ref": "#definitions/nodes" }
            }
          }
        },
        {
          "type": "object",
          "properties": {
            "edges": {
              "type": "array",
              "items": { "$ref": "#definitions/edges" }
            }
          }
        },
        {
          "type": "object",
          "properties": {
            "edgeAttribute": {
              "type": "array",
              "items": { "$ref": "#definitions/edgeAttribute" }
            }
          }
        },
        {
          "type": "object",
          "properties": {
            "nodeAttribute": {
              "type": "array",
              "items": { "$ref": "#definitions/nodeAttribute" }
            }
          }
        }
      ]
    },

    {
      "type": "object",
      "properties": {
        "status": {
          "type": "array",
          "items": { "$ref": "#definitions/status" }
        }
      },
      "required": ["status"]
    }
  ],

  "definitions": {
    "status": {
      "type": "object",
      "properties": {
        "success": { "type": "boolean" }
      }
      "etc..."
    }
  }
}

但是如果我定义一个空数组,它将被接受,如果数组只包含 3 个必需对象之一,它也会被接受。

那么有没有一种方法可以使用 json-schemas 来验证类似示例的内容?

实际场景中元数据中可能不止有 2 个对象,这就是我没有使用 if -> then -> else 条件的原因。如果解决方案是使用它们,请告诉我。

我建议将您的每个“类型”移动到 $defs 中以供参考。

{
  "$defs": {
    "nvObj": {
      "type": "object",
      "properties": {
        "nv": { "type": "array", "items": { "$ref": "#/$defs/nv" } }
      },
      "required": ["nv"]
    },
    ...  // other defitions
  }
}

(我已将 $ref 更新为使用 $defs 而不是 definitions,因为这是自草案 7 以来的新关键字。)

然后你可以把很多引用放到一个oneOf.

{
  "$defs": {
    ... // from above
  },
  "type": "array",
  "items": {
    "oneOf": [
      { "$ref": "#/$defs/nvObj" },
      ... // all of the other object definitions
    ]
  }
}

对于这种情况,您避免 if/then/else 是正确的。 oneOf 是最好的选择。

数据的结构使它变得粗略,但是您可以使用一些模式来获得您想要的行为。让我们一个接一个。

声明一个可以包含任意多个对象的数组

通常人们为此使用 oneOf,但我不推荐这样做,因为它可能会导致性能不佳和难以理解的错误消息。通常这意味着 if/then,但在这种情况下,您可以通过将项目定义为单个对象(每个对象一次只允许一个 属性)来获得良好的结果。

{
  "items": {
    "type": "object",
    "properties": {
      "nv": { "$ref": "#/definitions/nv" },
      "metadata": { "$ref": "#/definitions/metadata" },
      "status": { "$ref": "#/definitions/status" },
      "nodes": { "$ref": "#/definitions/nodes" },
      "edges": { "$ref": "#/definitions/edges" }
    },
    "minProperties": 1,
    "maxProperties": 1
  }
}

编辑:之前推荐dependencies,后来发现这个更好

断言数组包含一个需要的对象

为此,您需要断言数组 contains 是一个具有 required 属性.

的对象
{ "contains": { "type": "object", "required": ["nv"] } }

您必须在 allOf 中组合此模式来表达额外的必需项。

{
  "allOf": [
    { "contains": { "type": "object", "required": ["nv"] } },
    { "contains": { "type": "object", "required": ["metadata"] } },
    { "contains": { "type": "object", "required": ["status"] } }
  ]
}

有条件地断言数组包含一个需要的对象

这里棘手的部分是让 if 中的所有嵌套 containsproperties 能够断言“名称”是某个值。 then 只是使用我们上面使用的相同模式来断言数组中需要一个对象。

{
  "if": {
    "type": "array",
    "contains": {
      "type": "object",
      "properties": {
        "metadata": {
          "type": "array",
          "contains": {
            "type": "object",
            "properties": {
              "name": { "const": "nodes" }
            },
            "required": ["name"]
          }
        }
      },
      "required": ["metadata"]
    }
  },
  "then": { "contains": { "type": "object", "required": ["nodes"] } }
}

以上示例显示了有条件地需要“节点”对象。您需要为“边缘”对象重复此模式并将它们与 allOf 组合。我建议使用 definitions 来帮助提高可读性。

{
  "allOf": [
    { "$ref": "#/definitions/if-metadata-has-nodes-then-require-nodes-object" },
    { "$ref": "#/definitions/if-metadata-has-edges-then-require-edges-object" }
  ]
}