使用 JSON 模式验证 JSON 输入

问题描述 投票:0回答:1

如果您在输入文件中指定配置为架构中要求的元素,则验证正常。 如果您附加“maxItems”:1,它并不关心您是否在输入文件中添加另一个元素,验证器仍然将其视为有效的输入文件。

即: 架构:

{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "type": "object",
    "properties": {
        "Books": {
            "type": "object",
            "minItems": 1,
            "properties": {
                "Book": {
                    "type": "object",
                    "minItems": 1,
                    "maxItems": 1,
                    "properties": {
                        "Author": {
                            "type": "string",
                            "minItems": 1,
                            "maxItems": 1
                        }
                    },
                    "required": ["Author"]
                }
            },
            "required": ["Book"]
        }
    },
    "required": ["Books"]
}

输入文件:

{
    "Books": {
        "Book": {
            "Author": "Andreas",
            "Author": "Geir"
        }
    }
}

这不应该是一个无效的输入文件吗?

验证者:

json validation schema jsonschema json-schema-validator
1个回答
7
投票

根据您定义的架构,给定的 JSON 是正确的。 您的架构所说的是,对于每个对象

Author
,应该至少有 1 个、最多 1 个字符串属性,您的 JSON 符合这一点。
除此之外,属性
minItems
maxItems
专门用于 arrays,但在您的定义中,它们位于 objects 下。请在底部的链接文档中阅读更多相关信息。

令人困惑的部分是您期望数组是对象,而对象是数组,这有时很难区分。


简单来说:
JSON 对象key:value 对的集合。这就好像您正在定义一个对象(类)并用 OOP 语言设置它的属性值。
JSON 对象的基本定义:

{
  "type": "object",
  "properties": {
    "MyString": {
      "type": "string"
    },
    "MyInterger": {
      "type": "integer"
    }
}

JSON 数组是相同(有时是相似)对象或单个值的集合
JSON 数组的基本定义:

{
  "type": "array",
  "items": {
    "type": "string"
  }
}

还可以帮助定义何时使用什么,那就是想想你想要创建什么,但作为 OOP 语言中的对象。

示例:

对于以下

Book
JSON 对象,我可以想象一个如图所示的类结构,然后从中创建架构:

JSON:

{
  "Author": "First Author",
  "TotalPages": 128,
  "Chapters": [
    {
      "Number": 1,
      "Heading": "Chapter One"
    },
    {
      "Number": 2,
      "Heading": "Chapter Two"
    }
  ]
}

我们拥有的是

  • 两个 基本对象
    Author (string)
    TotalPages (integer)
  • Chapters对象的
    数组
    ,其中包含两个基本对象
    Number (integer)
    Heading (string)

班级代表:

public class Book
{
  public string Author { get; set; }
  public int TotalPages { get; set; }
  // Note the array
  public Chapter[] Chapters { get; set; } // Could be List<Chapter>
}

public class Chapter
{
  public int Number { get; set; }
  public string Heading { get; set; }
}

生成的架构:

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "Author": {
      "type": "string"
    },
    "TotalPages": {
      "type": "integer"
    },
    "Chapters": {
      "type": "array",
      "minItems": 1,
      "items": {
        "type": "object",
        "properties": {
          "Number": {
            "type": "integer"
          },
          "Heading": {
            "type": "string"
          }
        }
      }
    }
  },
  "required": ["Author", "Chapters"]
}


现在你会注意到我故意省略了“Books”部分,因为那是“Book”的*数组/集合*。如果我们想将其添加到 JSON 模式和类中,我们需要这样定义它。在我们这样做的同时,让我们为每本书添加一个字符串数组作为“关键字”,这样就可以清楚地了解如何定义每个关键字。

首先让我们更改所需的输出(JSON)。
我们希望我们的基础对象现在是

Books
,并且它应该是
Book
对象的集合,因此我们将
Book
对象包含在
[ ]
中,并添加另一本书。我们还将
Keywords
的集合添加到对象
Book

{
  "Books":
  [
    {
      "Author": "First Author",
      "TotalPages": 128,
      "Chapters": [
        {
          "Number": 1,
          "Heading": "Chapter One"
        },
        {
          "Number": 2,
          "Heading": "Chapter Two"
        }
      ],
      "Keywords": [
        "This",
        "is",
        "book",
        "Alpha"
      ]
    },
    {
      "Author": "Second Author",
      "TotalPages": 256,
      "Chapters": [
        {
          "Number": 1,
          "Heading": "Erstes Kapitel"
        },
        {
          "Number": 2,
          "Heading": "Zweites Kapitel"
        }
      ],
      "Keywords": [
        "This",
        "is just",
        "Beta"
      ]
    }
  ]
}

现在我们有以下内容:

  • 一个对象
    Books
    ,其中包含我们之前定义的Book对象的
    数组
    。 (请注意,
    Book
    从未被命名,因为这会在 JSON 中添加另一个层次结构)
  • 除了之前定义的对象之外,我们还有 string
     的数组
    ,代表
    Keywords

让我们更改 JSON 的 class/object 表示形式,这样做将有助于了解如何修改架构。

public class MyBookCollection
{
  // Note the array!!
  public Book[] Books { get; set; } // Could also be List<Book>
}

public class Book
{
  public string Author { get; set; }
  public int TotalPages { get; set; }
  // Note the arrays!!
  public Chapter[] Chapters { get; set; } // Could also be List<Chapter>
  public string[] Keywords { get; set; }  // Could also be List<string>
}

public class Chapter
{
  public int Number { get; set; }
  public string Heading { get; set; }
}

我们现在知道当我们最终解析 JSON 时,我们的 dataclass 会是什么样子。让我们更改 JSON 架构,以便我们拥有可以在验证器中使用的东西。

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "Books": {
      "type": "array",
      "minItems": 1,
      "maxItems": 15,
      "title": "Book",
      "items": {
        "type": "object",
        "properties": {
          "Author": {
            "type": "string"
          },
          "TotalPages": {
            "type": "integer"
          },
          "Chapters": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "object",
              "properties": {
                "Number": {
                  "type": "integer"
                },
                "Heading": {
                  "type": "string"
                }
              }
            }
          },
          "Keywords": {
            "type": "array",
            "minItems":2,
            "items": {
              "type": "string"
            }
          }
        },
        "required": ["Author", "Chapters"]
      }
    }
  }
}

我在 数组定义

中添加了一些 
minItems
maxItems ,以便您可以了解在何处以及如何设置它们。您可以将架构和数据复制到任何验证器并使用它们来了解它们是如何工作的。


还有一件重要的事情:
您无法通过架构验证来防止或检查对象内的重复属性。
作为示例,使用我们简单的 JSON 对象并添加重复的属性,

{
  "Author": "First Author",
  "Author": "!!Duplicate Author!!",
  "TotalPages": 128,
  "Chapters": [
    {
      "Number": 1,
      "Heading": "Chapter One"
    },
    {
      "Number": 2,
      "Heading": "Chapter Two"
    }
  ]
}

将该 JSON 转储到任何提到的验证器中,它们都将验证为 **正确** 和 **通过**。我检查过,并且在 [JSON Schema Google Group][6] 上确认了这一点,目前无法通过架构定义对其进行检查。

如何处理重复属性也是特定于库的。
例如,C# 的 Newtonsoft.JsonServiceStack 库都将使用最后一次出现的属性。
因此,从我们的示例来看,使用任一库反序列化后

Book.Author
属性的值将是“!!重复作者!!”。

一些来源:

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.