json - 如何在代码中定义包含定义的Json Schema

标签 json f# jsonschema

我正在尝试通过使用Json Schema在代码中定义架构来复制以下Newtonsoft.Json.Schema示例:

{
  "$schema": "http://json-schema.org/draft-04/schema#",

  "definitions": {
    "address": {
      "type": "object",
      "properties": {
        "street_address": { "type": "string" },
        "city":           { "type": "string" },
        "state":          { "type": "string" }
      },
      "required": ["street_address", "city", "state"]
    }
  },

  "type": "object",

  "properties": {
    "billing_address": { "$ref": "#/definitions/address" },
    "shipping_address": { "$ref": "#/definitions/address" }
  }

这与我到目前为止已经很近了。 (示例在F#中,但在C#中也可能一样。)

代码:
open Newtonsoft.Json.Schema
open Newtonsoft.Json.Linq

let makeSchema = 
    let addressSchema = JSchema()
    addressSchema.Properties.Add("street_address", JSchema(Type = Nullable(JSchemaType.String)))
    addressSchema.Properties.Add("city", JSchema(Type = Nullable(JSchemaType.String)))
    addressSchema.Properties.Add("state", JSchema(Type = Nullable(JSchemaType.String)))
    addressSchema.Required.Add "street_address"
    addressSchema.Required.Add "city"
    addressSchema.Required.Add "state"

    let schema = JSchema()
    schema.Properties.Add("billing_address", addressSchema)
    schema.Properties.Add("shipping_address", addressSchema)
    schema

输出:
{
  "properties": {
    "billing_address": {
      "properties": {
        "street_address": {
          "type": "string"
        },
        "city": {
          "type": "string"
        },
        "state": {
          "type": "string"
        }
      },
      "required": [
        "street_address",
        "city",
        "state"
      ]
    },
    "shipping_address": {
      "$ref": "#/properties/billing_address"
    }
  }
}

如您所见,两个地址中只有一个是通过使用对另一个模式的引用来定义的,并且该地址模式位于“属性”而不是“定义”中。在“定义”中定义架构并在其他地方引用它的诀窍是什么?

最佳答案

哈克节! :-)

根据source code的说法,JSON.NET Schema只是不编写definitions属性,这是故事的结尾。所以这一切都没有希望...几乎。

但是,它的确在其他地方使用了definitions属性。即-when generating schema from a type。在此过程中,它将创建一个JObject,将所有模式插入其中,然后将该对象添加到JSchema.ExtensionData键下的definitions中。当从另一个地方引用一个模式时,模式编写者将尊重该definitions对象(如果存在),从而使整个事情协同工作。

因此,有了这些知识,我们就可以破解我们的方法:

let makeSchema = 
    let addressSchema = JSchema()
    ...

    let definitions = JObject() :> JToken
    definitions.["address"] <- addressSchema |> JSchema.op_Implicit

    let schema = JSchema()
    schema.ExtensionData.["definitions"] <- definitions
    schema.Properties.Add("billing_address", addressSchema)
    schema.Properties.Add("shipping_address", addressSchema)
    schema

瞧!生成的模式现在具有definitions对象,正如神圣文本告诉我们的那样:
{
  "definitions": {
    "address": {
      "properties": {
        "street_address": {
          "type": "string"
        },
        "city": {
          "type": "string"
        },
        "state": {
          "type": "string"
        }
      },
      "required": [
        "street_address",
        "city",
        "state"
      ]
    }
  },
  "properties": {
    "billing_address": {
      "$ref": "#/definitions/address"
    },
    "shipping_address": {
      "$ref": "#/definitions/address"
    }
  }
}

一些注意事项:
  • 从JSON.NET的角度来看,definitions名称并不特殊。如果将schema.ExtensionData.["definitions"]行更改为其他内容(例如schema.ExtensionData.["xyz"]),它将仍然有效,并且所有引用均指向"#/xyz/address"
  • 显然,这整个机制是一个hack,显然不是according to James Netwon-King。关键的见解似乎是JsonSchemaWriter将能够查找任何先前提到的模式,并在其他地方使用对它们的引用。这样一来,只要有人喜欢,就可以将模式推送到任何地方,并希望它们被引用。
  • 那里的op_Implicit调用是必要的。 JSchema不是JToken的子类型,因此您不能像这样将其仅塞入definitions.["address"],必须先将其转换为JToken。幸运的是,为此定义了一个implicit cast operator。不幸的是,这并不简单,似乎正在发生一些魔术。这个happens transparently in C#(因为您知道并没有足够的困惑),但是在F#中,您必须显式调用它。
  • 关于json - 如何在代码中定义包含定义的Json Schema,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40483028/

    相关文章:

    json - 如何解码带有特殊字符的静态 JSON 文件

    java - jsonschema2pojo maven插件不生成Java类

    javascript - 使用 MIME 类型 application/json 可能会导致什么问题?

    java - 通过 GlassFish 服务器使用 REST - 如何允许使用 HTML 输入更新列表并返回 JSON 对象?

    f# - .fsx 文件是在 Debug模式还是 Release模式下交互编译的?

    F#过滤列表

    f# - 为什么这个定义返回一个函数?

    python - pkg_resources.DistributionNotFound : 'jsonschema'

    JSON Schema oneOf 属性已填充

    java - 当我尝试使用 Volley 将图像从 Android 上传到 PHP 服务器时出现错误(JSONException)