使用JSON-Schema验证数据,第2部分

在本教程的第一部分中,您学习了如何使用所有可用的验证关键字来创建相当高级的架构。 许多JSON数据的实际示例比我们的用户示例更复杂。 试图将所有要求放在这样的数据中的一个文件可能会导致非常大的架构,该架构也可能有很多重复项。

结构化架构

JSON模式的标准允许您将模式分为多个部分。 让我们看一下新闻站点导航的数据示例:

{
  "level": 1,
  "parent_id": null,
  "visitors": "all",
  "color": "white",
  "pages": [
    {
      "page_id": 1,
      "short_name": "home",
      "display_name": "Home",
      "url": "/home",
      "navigation": {
        "level": 2,
        "parent_id": 1,
        "color": "blue",
        "pages": [
          {
            "page_id": 11,
            "short_name": "headlines",
            "display_name": "Latest headlines",
            "url": "/home/latest",
            "navigation": {
              "level": 3,
              "parent_id": 11,
              "color": "white",
              "pages": [
                {
                  "page_id": 111,
                  "short_name": "latest_all",
                  "display_name": "All",
                  "url": "/home/latest"
                },
                ...
              ]
            }
          },
          {
            "page_id": 12,
            "short_name": "events",
            "display_name": "Events",
            "url": "/home/events"
          }
        ]
      }
    },
    ...
  ]
}

上面的导航结构与您在http://dailymail.co.uk网站上看到的导航结构有些相似。 您可以在GitHub存储库中看到一个更完整的示例。

数据结构复杂且递归,但是描述此数据的模式非常简单:

navigation.json:

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "id": "http://mynet.com/schemas/navigation.json#",
  "title": "Navigation",
  "definitions": {
    "positiveIntOrNull": { "type": ["null", "integer"], "minimum": 1 }
  },
  "type": "object",
  "additionalProperties": false,
  "required": [ "level", "parent_id", "color", "pages" ],
  "properties": {
    "level":     { "$ref": "defs.json#/definitions/positiveInteger" },
    "parent_id": { "$ref": "#/definitions/positiveIntOrNull" },
    "visitors":  { "enum": [ "all", "subscribers", "age18" ] },
    "color":     { "$ref": "defs.json#/definitions/color" },
    "pages":     {
      "type": "array",
      "items": { "$ref": "page.json#" }
    }
  }
}

page.json:

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "id": "http://mynet.com/schemas/page.json#",
  "title": "Page",
  "type": "object",
  "additionalProperties": false,
  "required": [ "page_id", "short_name", "display_name", "path" ],
  "properties": {
    "page_id":      { "$ref": "defs.json#/definitions/positiveInteger" },
    "short_name":   { "type": "string", "pattern": "^[a-z_]+$" },
    "display_name": { "type": "string", "minLength": 1 },
    "path":         { "type": "string", "pattern": "^(?:/[a-z_\-]+)+$" },
    "color":        { "$ref": "defs.json#/definitions/color" },
    "navigation":   { "$ref": "navigation.json#" }
  }
}

defs.json:

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "id": "http://mynet.com/schemas/defs.json#",
  "title": "Definitions",  
  "definitions": {
    "positiveInteger": { "type": "integer", "minimum": 1 },
    "color": {
      "anyOf": [
        { "enum": [ "red", "green", "blue", "white" ] },
        { "type": "string", "pattern": "^#(?:(?:[0-9a-fA-F]{1,2})){3}$" }
      ]
    }
  }
}

看一下上面的模式和它们描述的导航数据(根据模式navigation.json有效)。 需要注意的主要事情是,schema navigation.json引用了page.json架构,而page.json又引用了第一个。

用于根据模式验证用户记录JavaScript代码可以是:

var Ajv = require('ajv');
var ajv = Ajv({
  allErrors: true,
  schemas: [
    require('./navigation.json'),
    require('./page.json'),
    require('./defs.json')
  ]
});

var validate = ajv.getSchema("http://mynet.com/schemas/navigation.json#");
var valid = validate(navigationData);
if (!valid) console.log(validate.errors);

所有代码示例都可以在GitHub Repository中找到

示例中使用的验证器Ajv是JavaScript最快的JSON-Schema验证器。 我创建了它,因此在本教程中将使用它。 最后,我们将研究它与其他验证器的比较方式,以便您为自己选择合适的验证器。

任务

有关如何使用任务安装存储库以及测试答案的说明,请参见本教程的第1部分

使用“ $ ref”关键字的模式之间的引用

JSON-Schema标准允许您使用带有“ $ ref”关键字的引用来重复使用模式的重复部分。 从导航示例中可以看到,您可以引用位于的架构:

  • 在另一个文件中:使用在其“ id”属性中定义的架构URI
  • 在另一个文件的任何部分中:将JSON指针附加到架构引用
  • 在当前模式的任何部分中:将JSON指针附加到“#”

您还可以使用等于“#”的“ $ ref”引用整个当前架构,它允许您创建引用自己的递归架构。

因此,在我们的示例中, navigation.json的架构是指:

  • 模式page.json
  • 模式defs.json definitions
  • 在同一模式中定义positiveIntOrNull

page.json的模式指的是:

  • 回到schema navigation.json
  • 也可以definitions defs.json文件中的defs.json

该标准要求“ $ ref”应该是对象中的唯一属性,因此,如果要除了其他模式之外还应用引用的模式,则必须使用“ allOf”关键字。

任务1

使用参考重构本教程第1部分中的用户架构。 将模式分为两个文件: user.jsonconnection.json

将您的模式放入文件part2/task1/user.jsonpart2/task1/connection.json part2/task1/user.json part2/task1/connection.json然后运行node part2/task1/validate来检查您的模式是否正确。

JSON指针

JSON指针是定义JSON文件各部分路径的标准。 该标准在RFC6901中进行了描述。

该路径由与“ /”字符连接的段(可以是任何字符串)组成。 如果段中包含字符“〜”或“ /”,则应将其替换为“〜0”和“〜1”。 每个段表示JSON数据中的属性或索引。

如果您查看导航示例,则定义color属性的“ $ ref”是“ defs.json#/ definitions / color”,其中“ defs.json#”是架构URI,“ / definitions / color”是JSON指针。 它指向属性definitions内的属性color

约定是将引用中使用的架构的所有部分放在架构的definitions属性内(如示例中所示)。 尽管JSON模式用于此目的保留了definitions关键字,但是并不需要将子计划放在此处。 JSON-pointer允许您引用JSON文件的任何部分。

在URI中使用JSON指针时,应对URI中所有无效的字符进行转义(在JavaScript中,可以使用全局函数encodeURIComponent )。

不仅可以在JSON模式中使用JSON指针。 它们可用于表示JSON数据中任何属性或项目的路径。 您可以使用库jso

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值