1. 程式人生 > 實用技巧 >Json schema 以及在python中的jsonschema

Json schema 以及在python中的jsonschema

原文:https://www.cnblogs.com/ChangAn223/p/11234348.html

作者:長安223

1. JSON Schema簡介

JSON Schema是基於JSON格式,用於定義JSON資料結構以及校驗JSON資料內容。JSON Schema官網地址:http://json-schema.org/

要想完全理解的JSON Schema,我們首先需要了解JSON Schema中關鍵字的含義和作用。JSON Schema中比較常見的關鍵字如下:

關鍵字描述
$schema 表示該JSON Schema檔案遵循的規範
title 為該JSON Schema檔案提供一個標題
description 關於該JSON Schema檔案的描述資訊
type 表示待校驗元素的型別(例如,最外層的type表示待校驗的是一個JSON物件,內層type分別表示待校驗的元素型別為,整數,字串,數字)
properties 定義待校驗的JSON物件中,各個key-value對中value的限制條件
requiredv 定義待校驗的JSON物件中,必須存在的key
minimum 用於約束取值範圍,表示取值範圍應該大於或等於minimum
exclusiveMinimum 如果minimum和exclusiveMinimum同時存在,且exclusiveMinimum的值為true,則表示取值範圍只能大於minimum
maximum 用於約束取值範圍,表示取值範圍應該小於或等於maximum
exclusiveMaximum 如果maximum和exclusiveMaximum同時存在,且exclusiveMaximum的值為true,則表示取值範圍只能小於maximum
multipleOf 用於約束取值,表示取值必須能夠被multipleOf所指定的值整除
maxLength 字串型別資料的最大長度
minLength 字串型別資料的最小長度
pattern 使用正則表示式約束字串型別資料

2. JSON Schema關鍵字詳解

例一:涉及的關鍵字($schema、title、description、type、properties、required)

完整的python程式碼:

# 匯入驗證器
from jsonschema import validate

# 編寫schema:
my_schema = {
    "$schema": "http://json-schema.org/draft-04/schema#",
    "title": "TestInfo",
    "description": "some information about test",
    "type": "object",
    "properties": {
        "name": {
            "description": "Name of the test",
            "type": "string"
        },
        "age": {
            "description": "age of test",
            "type": "integer"
        }
    },
    "required": [
        "name", "age"
    ]
}

# json資料:
json_data = {
    "name": "python",
    "age": 25
}

# 驗證:
validate(instance=json_data, schema=my_schema)

validate() 函式將首先驗證所提供的模式本身是否有效,因為不這樣做會導致不太明顯的錯誤訊息,並以不太明顯或一致的方式失敗。然後再驗證json資料。
如果JSON資料例項是無效的,則丟擲 jsonschema.exceptions.ValidationError 異常
如果schema模式本身是無效的,則丟擲 jsonschema.exceptions.SchemaError 異常

2.1 $schema

該關鍵字用於指定JSON Schema版本資訊,例一中指定的版本為:draft-04。該關鍵字是可以省略的,當前最新版本為draft-07。注意:該關鍵字的值必須使用官方提供的值,不能自己隨便寫。

2.2 title和description

這兩個關鍵字都是用來描述對應的JSON元素的,唯一的區別在於,title相對來說,更加簡潔,而description更加傾向於詳細描述相關資訊。當然了,這兩個關鍵字都是可以省略的。我們看到例一中最外層的title和description是對待校驗JSON物件的描述,而其中,name元素之下的description其實是對待校驗JSON物件的一級key(name)的描述,當然,你也可以對name增加title資訊。

2.3 type

該關鍵字用於限定待校驗JSON元素所屬的資料型別,例一中最外層的type關鍵字值為object,即表示待校驗JSON資料為一個JSON物件,而name下的type關鍵字值為string,即表示待校驗JSON物件中的一級key(name)的資料型別為string。那麼,按照這個要求,下面這個JSON資料是符合要求的。

{
    "name": "hello first blog"
}

而,下面這個JSON資料是不符合要求的,因為name的型別為integer或者number,而不是string。

{
    "name": 520
}

3 type常見取值

那麼,type又有哪些取值呢?當type取值為string型別的時候,是否還可以新增其他一些附加限制條件呢?我們接下來會按照type的不同取值一點點分析涉及到的關鍵字含義及用法。首先,我們來看一下,type常見的取值。具體如下:

type取值對應的python資料型別
object Object
array List
integer int
number float或int
null None
boolean .Boolean
string String

在上表中,我們採用了和Java資料型別對比分析的形式給出了type的常見取值,接下來,我們會分析當type為不同取值時,可能涉及的關鍵字含義和用法。


3.1 當type取值為object時

涉及的關鍵字:properties、required、minProperties、maxProperties、propertyNames、dependencies、patternProperties、additionalProperties

properties

該關鍵字的值是一個物件。

用於指定JSON物件中的各種不同key應該滿足的校驗邏輯,如果待校驗JSON物件中所有值都能夠通過該關鍵字值中定義的對應key的校驗邏輯,每個key對應的值,都是一個JSON Schema,則待校驗JSON物件通過校驗。從這裡,我們可以看到,只要待校驗JSON物件的所有key分別都通過對應的JSON Schema的校驗檢測,這個物件才算是通過校驗。

另外,需要注意的是,省略該關鍵字和該關鍵字的值為空物件,具有相同效果。例如:

"properties": {
        "id": {
            "description": "The unique identifier for a book",
            "type": "integer",
            "minimum": 1
        },
        "price": {
            "type": "number",
            "minimum": 0,
            "exclusiveMinimum": true
        }
    }

required

該關鍵字的值是一個數組,而陣列中的元素必須是字串,而且必須是唯一的。

該關鍵字限制了JSON物件中必須包含哪些一級key。如果一個JSON物件中含有required關鍵字所指定的所有一級key,則該JSON物件能夠通過校驗。

另外,需要注意的是,省略該關鍵字和該關鍵字的值為空陣列,具有相同效果。例如:

"required": [
        "id",
        "name",
        "price"
    ]

minProperties、maxProperties

這兩個關鍵字的值都是非負整數。

指定了待校驗JSON物件中一級key的個數限制,minProperties指定了待校驗JSON物件可以接受的最少一級key的個數,而maxProperties指定了待校驗JSON物件可以接受的最多一級key的個數。

另外,需要注意的是,省略minProperties關鍵字和該關鍵字的值為0,具有相同效果。而,如果省略maxProperties關鍵字則表示對一級key的最大個數沒有限制。例如,如果限制一個JSON物件的一級key的最大個數為5,最小個數為1,則JSON Schema如下:

"minProperties": 1,
"maxProperties": 5

propertyNames

注意:該關鍵字,官方說明中支援,但是,有可能你使用的平臺或者第三方工具不支援哦。所以,使用需謹慎。

該關鍵字的值是一個有效的JSON Schema。

如果待校驗JSON物件中的每個一級key都能通過該關鍵字指定的JSON Schema的校驗,那麼才認為待校驗的JSON物件通過校驗。注意,待校驗JSON物件的一級key都是string型別。

另外,需要注意的是,省略該關鍵字和該關鍵字的值為空JSON Schema,具有相同效果。

patternProperties

該關鍵字的值是一個JSON物件,該JSON物件的每一個一級key都是一個正則表示式,value都是一個JSON Schema。

只有待校驗JSON物件中的一級key,通過與之匹配的patternProperties中的一級正則表示式,對應的JSON Schema的校驗,才算通過校驗。例如,如果patternProperties對應的值如下:

"patternProperties": {
        "^a": {
            "type": "number"
        },
        "^b": {
            "type": "string"
        }
}

上面的JSON Schema表示,待校驗JSON物件中,所有以a開頭的一級key的value都必須是number,所有以b開頭的一級key的value都必須是string。

additionalProperties

該關鍵字的值是一個JSON Schema。

如果待校驗JSON物件中存在,既沒有在properties中被定義,又沒有在patternProperties中被定義,那麼這些一級key必須通過additionalProperties的校驗。

dependencies

待定。。。

完整示例:

{
    "type": "object",
    "properties": {
        "id": {
            "description": "The unique identifier for a book",
            "type": "integer",
            "minimum": 1
        },
        "price": {
            "type": "number",
            "minimum": 0,
            "exclusiveMinimum": true
        }
    },
    "patternProperties": {
        "^a": {
            "type": "number"
        },
        "^b": {
            "type": "string"
        }
    },
    "additionalProperties": {
        "type": "number"
    },
    "minProperties": 1,
    "maxProperties": 5,
    "required": [
        "id",
        "name",
        "price"
    ]
}

3.2 當type取值為array時

涉及的關鍵字:items、additionalItems、minItems、maxItems、uniqueItems、contains

items

該關鍵字的值是一個有效的JSON Schema或者一組有效的JSON Schema。

當該關鍵字的值是一個有效的JSON Schema時,只有待校驗JSON陣列中的所有元素均通過校驗,整個陣列才算通過校驗。例如,如果items關鍵字的具體定義如下:

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

上面的JSON Schema的意思是,待校驗JSON陣列的元素都是string型別,且最小可接受長度是5。那麼下面這個JSON陣列明顯是符合要求的,具體內容如下:

["myhome", "green"]

那麼下面這個JSON資料則是不符合要求,因為第一個元素的長度小於5,具體內容如下:

["home", "green"]

當該關鍵字的值是一組有效的JSON Schema時,只有待校驗JSON陣列的所有元素通過items的值中對應位置上的JSON Schema的校驗,那麼,整個待校驗JSON陣列才算通過校驗。

這裡需要注意的是,如果items定義的有效的JSON Schema的數量和待校驗JSON陣列中元素的數量不一致,那麼就要採用“取小原則”。即,如果items定義了3個JSON Schema,但是待校驗JSON陣列只有2個元素,這時,只要待校驗JSON陣列的前兩個元素能夠分別通過items中的前兩個JSON Schema的校驗,那麼,我們認為待校驗JSON陣列通過了校驗。而,如果待校驗JSON陣列有4個元素,這時,只要待校驗JSON陣列的前三個元素能夠通過items中對應的JSON Schema的校驗,我們就認為待校驗JSON陣列通過了校驗。

例如,如果items的值如下:

{
    "type": "array",
    "items": [
        {
            "type": "string",
            "minLength": 5
        },
        {
            "type": "number",
            "minimum": 10
        },
        {
            "type": "string"
        }
    ]
}

上面的JSON Schema指出了待校驗JSON陣列應該滿足的條件,陣列的第一個元素是string型別,且最小可接受長度為5,陣列的第二個元素是number型別,最小可接受的值為10,陣列的第三個元素是string型別。那麼下面這兩個JSON陣列明顯是符合要求的,具體內容如下:

["green", 10, "good"]
["helloworld", 11]

下面這兩個JSON陣列卻是不符合要求的,具體內容如下:

["green", 9, "good"]
["good", 12]

additionalItems

該關鍵字的值是一個有效的JSON Schema。

需要注意的是,該關鍵字只有在items關鍵字的值為一組有效的JSON Schema的時候,才可以使用,用於規定超出items中JSON Schema總數量之外的待校驗JSON陣列中的剩餘的元素應該滿足的校驗邏輯。當然了,只有這些剩餘的所有元素都滿足additionalItems的要求時,待校驗JSON陣列才算通過校驗。

其實,你可以這麼理解,當items的值為一組有效的JOSN Schema的時候,一般可以和additionalItems關鍵字組合使用,items用於規定對應位置上應該滿足的校驗邏輯,而additionalItems用於規定超出items校驗範圍的所有剩餘元素應該滿足的條件。如果二者同時存在,那麼只有待校驗JSON陣列同時通過二者的校驗,才算真正地通過校驗。

另外,需要注意的是,如果items只是一個有效的JSON Schema,那麼就不能使用additionalItems,原因也很簡單,因為items為一個有效的JSON Schema的時候,其規定了待校驗JSON陣列所有元素應該滿足的校驗邏輯。additionalItems已經沒有用武之地了。

最後,同樣強調一下,省略該關鍵字和該關鍵字的值為空JSON Schema,具有相同效果。

如果一個additionalItems的值如下:

{
    "type": "array",
    "items": [
        {
            "type": "string",
            "minLength": 5
        },
        {
            "type": "number",
            "minimum": 10
        }
    ],
    "additionalItems": {
        "type": "string",
        "minLength": 2
    }
}

上面的JSON Schema的意思是,待校驗JSON陣列第一個元素是string型別,且可接受的最短長度為5個字元,第二個元素是number型別,且可接受的最小值為10,剩餘的其他元素是string型別,且可接受的最短長度為2。那麼,下面三個JSON陣列是能夠通過校驗的,具體內容如下:

["green", 10, "good"]
["green", 11]
["green", 10, "good", "ok"]

下面JSON陣列是無法通過校驗的,具體內容如下:

["green", 10, "a"]
["green", 10, "ok", 2]

minItems、maxItems

這兩個關鍵字的值都是非負整數。

指定了待校驗JSON陣列中元素的個數限制,minItems指定了待校驗JSON陣列可以接受的最少元素個數,而maxItems指定了待校驗JSON陣列可以接受的最多元素個數。

另外,需要注意的是,省略minItems關鍵字和該關鍵字的值為0,具有相同效果。而,如果省略maxItems關鍵字則表示對元素的最大個數沒有限制。例如,如果限制一個JSON陣列的元素的最大個數為5,最小個數為1,則JSON Schema如下:

"minItems": 1,
"maxItems": 5

uniqueItems

該關鍵字的值是一個布林值,即boolean(true、false)。

當該關鍵字的值為true時,只有待校驗JSON陣列中的所有元素都具有唯一性時,才能通過校驗。當該關鍵字的值為false時,任何待校驗JSON陣列都能通過校驗。

另外,需要注意的是,省略該關鍵字和該關鍵字的值為false時,具有相同的效果。例如:

"uniqueItems": true
contains

注意:該關鍵字,官方說明中支援,但是,有可能你使用的平臺或者第三方工具不支援哦。所以,使用需謹慎。

該關鍵字的值是一個有效的JSON Schema。

只有待校驗JSON陣列中至少有一個元素能夠通過該關鍵字指定的JSON Schema的校驗,整個陣列才算通過校驗。

另外,需要注意的是,省略該關鍵字和該關鍵字的值為空JSON Schema具有相同效果。

完整示例:

{
    "type": "array",
    "items": [
        {
            "type": "string",
            "minLength": 5
        },
        {
            "type": "number",
            "minimum": 10
        }
    ],
    "additionalItems": {
        "type": "string",
        "minLength": 2
    },
    "minItems": 1,
    "maxItems": 5,
    "uniqueItems": true
}

3.3 當type取值為integer或number時

涉及的關鍵字:multipleOf、maximum、exclusiveMaximum、minimum、exclusiveMinimum

我們首先來回顧一下integer和number的區別,integer相當於python中的int型別,而number相當於python中的int或float型別。

multipleOf

該關鍵字的值是一個大於0的number,即可以是大於0的int,也可以是大於0的float。

只有待校驗的值能夠被該關鍵字的值整除,才算通過校驗。

如果含有該關鍵字的JSON Schema如下:

{
    "type": "integer",
    "multipleOf": 2
}

那麼,2、4、6都是可以通過校驗的,但是,3、5、7都是無法通過校驗的,當然了,2.0、4.0也是無法通過校驗的,但是,並不是因為multipleOf關鍵字,而是因為type關鍵字。

如果含有multipleOf關鍵字的JSON Schema如下:

{
    "type": "number",
    "multipleOf": 2.0
}

那麼,2、2.0、4、4.0都是可以通過校驗的,但是,3、3.0、3、3.0都是無法通過校驗的。

另外,需要注意的是,省略該關鍵字則不對待校驗數值進行該項校驗。

maximum

該關鍵字的值是一個number,即可以是int,也可以是float。

該關鍵字規定了待校驗元素可以通過校驗的最大值。即傳入的值必須小於maximum。

省略該關鍵字,即表示對待校驗元素的最大值沒有要求。

exclusiveMaximum

該關鍵字的值是一個number。

該關鍵字和maximum一樣,規定了待校驗元素可以通過校驗的最大值,不同的是待校驗元素可以等於exclusiveMaximum指定的值。即比maximum多了一個他自身這個邊界值

例如:

{
    "type": "number",
#  設定 maximum 為12.3 則傳入值必須小於12.3
#    "maximum": 12.3,
#  設定 exclusiveMaximum為12.3 則傳入值是小於等於12.3
    "exclusiveMaximum": 12.3
}

minimum、exclusiveMinimum

minimum、exclusiveMinimum關鍵字的用法和含義與maximum、exclusiveMaximum相似。唯一的區別在於,一個約束了待校驗元素的最小值,一個約束了待校驗元素的最大值。這裡就不展開解釋了。

完整示例:

{
    "type": "number",
    "multipleOf": 0.5,
#    "maximum": 12.5,
    "exclusiveMaximum": 12.5,
#    "minimum": 2.5,
    "exclusiveMinimum": 2.5
}

3.4 當type取值為string時

涉及的關鍵字:maxLength、minLength、pattern、format

maxLength

該關鍵字的值是一個非負整數。

該關鍵字規定了待校驗JSON元素可以通過校驗的最大長度,即待校驗JSON元素的最大長度必須小於或者等於該關鍵字的值。

另外,需要注意的是,如果省略該關鍵字則表示對待校驗元素的最大長度沒有限制。

minLength

該關鍵字的值是一個非負整數。

該關鍵字規定了待校驗JSON元素可以通過校驗的最小長度,即待校驗JSON元素的最小長度必須大於或者等於該關鍵字的值。

另外,需要注意的是,如果省略該關鍵字和該關鍵字的值為0,具有相同效果。

pattern

該關鍵字的值是一個正則表示式。

只有待校驗JSON元素符合該關鍵字指定的正則表示式,才算通過校驗。

format

該關鍵字的值可以是以下取值:

date、date-time(時間格式)、email(郵件格式)、hostname(網站地址格式)、ipv4、ipv6、uri等等。


{
    "type": "string",
    "format": "email"
}

使用format關鍵字時,在例項化validator時必須給它傳format_checker引數,fromat_checker引數的值即使各種版本的JSON模式規範的驗證器類,如:
Draft 7
Draft 6
Draft 4
Draft 3

當你例項化validator時,如果沒有給它傳format_checker引數, jsonschema是不會自動校驗schema中的format關鍵字的.因此,你需要做以下步驟:
1.額外匯入JSON Schema某個版本的模式規範如:from jsonschema import draft7_format_checker
2.例項化validator時傳入:validate(instance=json_data, schema=my_schema, format_checker=draft7_format_checker)

3.5 全型別可用

即不侷限於某個type,涉及的關鍵字:enum、const、allOf、anyOf、oneOf、not、default

enum

該關鍵字的值是一個數組,該陣列至少要有一個元素,且陣列內的每一個元素都是唯一的。

如果待校驗的JSON元素和陣列中的某一個元素相同,則通過校驗。否則,無法通過校驗。

注意,該陣列中的元素值可以是任何值,包括null。省略該關鍵字則表示無須對待校驗元素進行該項校驗。例如:

{
    "type": "number",
    "enum": [2, 3, null, "hello"]
}

const

該關鍵字的值可以是任何值,包括null。

如果待校驗的JSON元素的值和該關鍵字指定的值相同,則通過校驗。否則,無法通過校驗。

省略該關鍵字則表示無須對待校驗元素進行該項校驗。

注意,該關鍵字部分第三方工具,並不支援。

allOf

該關鍵字的值是一個非空陣列,數組裡面的每個元素都必須是一個有效的JSON Schema。

只有待校驗JSON元素通過陣列中所有的JSON Schema校驗,才算真正通過校驗。

anyOf

該關鍵字的值是一個非空陣列,數組裡面的每個元素都必須是一個有效的JSON Schema。

如果待校驗JSON元素能夠通過陣列中的任何一個JSON Schema校驗,就算通過校驗。

oneOf

該關鍵字的值是一個非空陣列,數組裡面的每個元素都必須是一個有效的JSON Schema。

如果待校驗JSON元素能且只能通過陣列中的某一個JSON Schema校驗,才算真正通過校驗。不能通過任何一個校驗和能通過兩個及以上的校驗,都不算真正通過校驗。

not

該關鍵字的值是一個JSON Schema。

只有待校驗JSON元素不能通過該關鍵字指定的JSON Schema校驗的時候,待校驗元素才算通過校驗。

default

該關鍵字的值是沒有任何要求的。

該關鍵字常常用來指定待校驗JSON元素的預設值,當然,這個預設值最好是符合要求的,即能夠通過相應的JSON Schema的校驗。

另外,需要注意的是,該關鍵字除了提示作用外,並不會產生任何實質性的影響。

3.6 再說type關鍵字

需要特別注意的是,type關鍵字的值可以是一個string,也可以是一個數組。

如果type的值是一個string,則其值只能是以下幾種:null、boolean、object、array、number、string、integer。

如果type的值是一個數組,則陣列中的元素都必須是string,且其取值依舊被限定為以上幾種。只要帶校驗JSON元素是其中的一種,則通過校驗。

4 JSON Schema比較複雜的示例:

from jsonschema import validate, draft7_format_checker
from jsonschema.exceptions import SchemaError, ValidationError


schema = {
    "$schema": "http://json-schema.org/draft-07/schema#",
    "title": "book info",
    "description": "some information about book",
    "type": "object",
    "properties": {
        "id": {
            "description": "The unique identifier for a book",
            "type": "integer",
            "minimum": 1
        },
        "name": {
            "description": "book name",
            "type": "string",
            "minLength": 3,
            "maxLength": 30
        },
        "info": {
            "description": "simple information about book",
            "type": "string",
            "minLength": 10,
            "maxLength": 60
        },
        "price": {
            "description": "book price",
            "type": "number",
            "multipleOf": 0.5,
            # 這裡沒有取等,5.0<price<99999.0
            "minimum": 5.0,
            "maximum": 99999.0,
            # 若使用下面這兩個關鍵字則 5.0<=price<=99999.0
            # "exclusiveMinimum": 5.0,
            # "exclusiveMaximum": 99999.0
        },
        "tags": {
            "type": "array",
            "items": [
                {
                    "type": "string",
                    "minLength": 2,
                    "macLength": 8
                },
                {
                    "type": "number",
                    "minimum": 1.0
                }
            ],
            "additonalItems": {
                "type": "string",
                "miniLength": 2
            },
            "miniItems": 1,
            "maxItems": 5,
            "uniqueItems": True
        },
        "date": {
            "description": "書籍出版日期",
            "type": "string",
            "format": "date",
        },
        "bookcoding": {
            "description": "書籍編碼",
            "type": "string",
            "pattern": "^[A-Z]+[a-zA-Z0-9]{12}$"
        },
        "other": {
            "description": "其他資訊",
            "type": "object",
            "properties": {
                "info1": {
                    "type": "string"
                },
                "info2": {
                    "type": "string"
                }
            }
        }
    },
    "minProperties": 3,
    "maxProperties": 7,
    "required": [
        "id", "name", "info", "price"
    ]
}

json_data = {
    "id": 1,
    "name": "jarvis手冊",
    "info": "賈維斯平臺使用手冊1",
    "price": 5.5,
    "tags": ["jar"],
    "date": "2019-5-25",
    "other": {
        "info1": "1111",
        "info2": "222"
    }
}


try:
    validate(instance=json_data, schema=schema, format_checker=draft7_format_checker)
except SchemaError as e:
    print("驗證模式schema出錯:\n出錯位置:{}\n提示資訊:{}".format(" --> ".join([i for i in e.path]), e.message))
except ValidationError as e:
    print("json資料不符合schema規定:\n出錯欄位:{}\n提示資訊:{}".format(" --> ".join([i for i in e.path]), e.message))
else:
    print("驗證成功!")

注意,以上JSON Schema只是為了展示部分關鍵字的用法,可能和實際應用略有不同。

官方的參考文件如下:http://json-schema.org/latest/json-schema-validation.html

參考文章:https://blog.csdn.net/qiumengchen12/article/details/77067613