使用JSON模式验证JSON输入

And*_*rud 0 validation schema json jsonschema json-schema-validator

如果在输入文件中指定在架构中配置为要求的元素,则验证是否正常.如果你附加"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"]
}
Run Code Online (Sandbox Code Playgroud)

输入文件:

{
    "Books": {
        "Book": {
            "Author": "Andreas",
            "Author": "Geir"
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

验证人:

Ber*_*nde 5

根据您定义的模式,给定的JSON是正确的.您的架构所说的是,对于每个对象Author,应该至少有1个,最多1个字符串属性,这是JSON符合的.
除此之外,属性minItemsmaxItems特定于数组,但在您的定义中,它们在对象下.在底部的链接文档中阅读更多相关信息.

混淆的部分是你期望数组是对象和对象是数组,有时很难区分.


简单来说:
JSON对象是一个键:值对.就好像您正在定义一个对象(类)并用OOP语言设置它的属性值.JSON对象的
基本定义:

{
  "type": "object",
  "properties": {
    "MyString": {
      "type": "string"
    },
    "MyInterger": {
      "type": "integer"
    }
}
Run Code Online (Sandbox Code Playgroud)

JSON阵列是一个集合是相同的,有时类似,对象或单值的.JSON数组的
基本定义:

{
  "type": "array",
  "items": {
    "type": "string"
  }
}
Run Code Online (Sandbox Code Playgroud)

什么也可以帮助定义什么时候使用,是想要你想要创建什么,但作为OOP语言中的对象.

例:

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

JSON:

{
  "Author": "First Author",
  "TotalPages": 128,
  "Chapters": [
    {
      "Number": 1,
      "Heading": "Chapter One"
    },
    {
      "Number": 2,
      "Heading": "Chapter Two"
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

我们拥有的是什么

  • 两个基本对象 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; }
}
Run Code Online (Sandbox Code Playgroud)

生成的架构:

{
  "$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"]
}
Run Code Online (Sandbox Code Playgroud)



现在,你会发现我特意留出的Books部分,因为这是一个数组/集合Book.如果我们想将它添加到JSON模式和类中,我们将需要将其定义为这样.虽然我们在这里,但是我们还要为每本书添加一个字符串数组Keywords,这样就很清楚如何定义每个字符串.

首先让我们改变我们想要的输出(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"
      ]
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

现在我们有以下内容:

  • 一个对象Books包含一个阵列我们的先前所定义的Book对象.(注意,Book永远不会命名,因为这会在JSON中添加另一层次的层次结构)
  • 除了我们前面定义的对象,我们也有一个数组string代表Keywords

让我们更改我们的JSON的类/对象表示,这样做有助于了解如何修改模式.

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; }
}
Run Code Online (Sandbox Code Playgroud)

我们现在知道当我们最终解析JSON时我们的数据会是什么样子.让我们更改JSON Schema,以便我们可以在验证器中使用.

{
  "$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"]
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我加了一些minItemsmaxItems数组的定义,这样就可以看到在何处以及如何对其进行设置.您可以将架构和数据复制到任何验证器,并使用它们来查看它们的工作方式.


另一个重要的事情是:
您无法通过Schema验证来阻止或检查对象内的重复属性.
例如,使用我们的简单JSON对象并添加重复属性,

{
  "Author": "First Author",
  "Author": "!!Duplicate Author!!",
  "TotalPages": 128,
  "Chapters": [
    {
      "Number": 1,
      "Heading": "Chapter One"
    },
    {
      "Number": 2,
      "Heading": "Chapter Two"
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)


将JSON转储到所提到的任何验证器中,它们都将验证为正确通过.我检查过,这在JSON Schema Google Group上得到了确认,目前无法通过架构定义检查它.

如何处理重复属性也是特定于库的.
例如,C#的Newtonsoft.JsonServiceStack库都将使用最后一次出现的属性.
因此,从我们的示例中,Book.Author使用任一库进行反序列化后的属性值将为"!! Duplicate Author !!".

一些来源: