JSON schema conditional check on certain object attribute within an array

允我心安 提交于 2020-03-03 10:54:05

问题


What I want to do either via AJV - JSON Schema validation or Custom Keywords (preferably I would go with this): The Array can have 1 or 2 JSON objects with type as 'admin' and 'guest'. The "type":"guest" object will always be there and "type":"admin" object is optional.

Extra Notes:

-The object itself may contain addition attributes and nested objects, in future

-The other valid enums aresuperadmin, admin,user and guest

-The type sequence in array is: superadmin, admin,user and guest. Is it possible to check the sequence? (although its optional)

-The 'guest' type object will always be there and there will be a unique type of object. If any re-occurence any object type (e.g. superadmin, admin,user and guest) then its an error

//Here is the schema:

{
"type": "object",
"properties": {
  "type": "array",
  "items": {
    "type": "object",
    "properties": {
      "type": { "enum": ["guest", "admin"]
    },
    "rights": {"type": "string"},
    "hyperLink": {"type": "string", "format": "uri"}
    }
  }
  }
}

I need to add 'checkTypeAndValue' flag somewhere in the json so that I can grab the complete JSON object and the corresponding attributes to do a programmatic check?

const checkTypeAndValue = function (schema, completeJSONObj) {
 //
};

ajv.addKeyword('checkTypeAndValue', {
  validate: checkTypeAndValue,
  errors: true
});

and here are some valid and invalid examples:

/Valid 1: As type is 'admin' and so 'rights' SHOULD NOT be in 'guest' object
{
  [
    {
      "type":"admin",
      "hyperLink": "http://www.someguest.com",
      "rights":"all"
    },
    {
      "type":"guest",
      "hyperLink": "http://www.someadmin.com"
    }
  ]
}

//Valid 2: You can have a SINGLE 'guest' object. 'admin' object is not required all the time
{
  [
    {
      "type":"guest",
      "hyperLink": "http://www.someadmin.com",
      "rights": "limited" //MANDATORY or REQUIRED Attribute
    }
  ]
}

//InValid
{
  [
    {
      "type":"admin",
      "hyperLink": "http://www.someguest.com",
      "rights":"all"
    },
    {
      "type":"guest",
      "hyperLink": "http://www.someadmin.com",
      "rights":"limited"
      //Error ==> As rights=all is there in 1st object, you cannot set 'rights' to any value including blank even having 'rights' attribute is not valid.
    }
  ]
}

Here is the if else condition that I need to sort out:

//Assuming admin object exist with rights....
if( type == admin && rights != ""){
  if(type == guest && rights attribute is there && rights != ""){
    //The 'guest' object will always be there....
    //error: guest 'rights' cannot have a value if type is 'admin' and rights is 'all' or any other value.
  }
}else{
   //Assuming mandatory guest object exist with rights....
   if(guest.rights does not exist OR guest.rights == "")
    //Error: 'rights' is MANDATORY attribute in guest block and error if its empty
   else 
    //Everything is fine
}

Also is there any way by which we can check in an array that there will be only one pair of object of certain type? For example: only one 'guest, 'admin' type. Error, if there are more than one type of 'guest' or 'admin'

//Complete example

{
  [
    {
      "type":"superadmin",
      "hyperLink": "http://www.superadmin.com"      
    },
    {
      "type":"admin",
      "hyperLink": "http://www.admin.com",
      "rights":"all"
    },
    {
      "type":"user",
      "hyperLink": "http://www.user.com"
    },
    {
      "type":"guest",
      "hyperLink": "http://www.guest.com"
    }
  ]
}

回答1:


It may seem a little tricky to do this with JSON Schema, but it is possible.

You need to be able conditionally check a negative condition.

So, you'll need to use a combination of if and then, with not.

First the condition: if there's an admin user. Using if, we can then conditionally apply the further checking rule.

Next, the check: guest user cannot have rights.

then is applied when if passes validation. We then need to negate a check that a guest has rights, using not.

You can see this correctly failing validation with the example expected invalid JSON data you provided using https://jsonschema.dev (link is pre-loaded with this schema and your provided instance data. It uses AJV in browser btw.)


Update: I've updated the schema to meet your additional requirements. I've also updated the demo link above.

The schema now only allows admin to have rights if admin is present, and no other user type may have rights if admin is present. Also one item in the array must have rights (as you required).

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "array",
  "if": {
    "contains": {
      "required": [
        "type"
      ],
      "properties": {
        "type": {
          "const": "admin"
        }
      }
    }
  },
  "then": {
    "not": {
      "contains": {
        "required": [
          "type",
          "rights"
        ],
        "properties": {
          "type": {
            "not": {
              "const": "admin"
            }
          }
        }
      }
    }
  },
  "contains": {
    "type": "object",
    "required": ["rights"]
  },
  "items": {
    "type": "object",
    "properties": {
      "type": {
        "enum": [
          "guest",
          "admin"
        ]
      },
      "rights": {
        "type": "string"
      },
      "hyperLink": {
        "type": "string",
        "format": "uri"
      }
    }
  }
}


来源:https://stackoverflow.com/questions/58135703/json-schema-conditional-check-on-certain-object-attribute-within-an-array

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!