JsonSchema - Defining a white-listed set of values - jsonschema

I feel like there's no chance my question was not asked before, but I couldn't find an answer anywhere.
As the title suggests, I'm trying to create a JSON schema that will validate an array if, and only if, All of the values in it are defined in a pre-defined set.
For example:
If the predefined set contains {"One", "Two", "Three"}, and the array I'm trying to validate is ["One", "Two"], then the array should be valid.
But if the array is ["One", "Two", "Four"], then the array would be invalid.
So I know of enum but it doesn't accomplish my goal since it validates as long as ONE of the values is defined in the predefined set.
I also know of min/max-contain combinations, tho they may interfere with the requirement that none of the values in the predefined set MUST appear. They all may, or may not appear.
Does anyone have an idea how to accomplish such requirements?

Okay, let's break that down:
You want to validate each item of an array against a schema. That's the items keyword: https://json-schema.org/understanding-json-schema/reference/array.html#items
each item of the array should have a value that exists in a predefined set. That's the enum keyword: https://json-schema.org/understanding-json-schema/reference/generic.html#id4
Putting it together:
{
"type": "array",
"items": {
"enum": [ "one", "two", "three" ]
}
}

Related

Kafka Lenses SQL - How to WHERE filter based on objects nested in an array

I am working in Kafka Lenses v2.2.2. I need to filter based on a the value of an object inside an array.
Sample message (redacted for simplicity):
{
"payload": {
"Data": {
"something" : "stuff"
},
"foo": {
"bar": [
{
"id": "8177BE12-F69B-4A51-B12E-976D2AE37487",
"info": "more_data"
},
{
"id": "06A846C5-2138-4107-A5B0-A2FC21B9F32D",
"info": "more_data"
}
]
}
}
In lenses this actually appears as a nested object with a integer properties... 0, 1, etc.
So I've tried this, but it is throwing an error: .0 appears out of place
SELECT *
FROM topic_name
WHERE payload.foo.bar.0.id = "8177BE12-F69B-4A51-B12E-976D2AE37487"
LIMIT 10
I tried wrapping the 0 in double/single quotes as well and that throws a 500 error.
I copied and pasted the UUID from the first message in the topic, so it's definitely there. I also copy and pasted the labels to rule out typos. I am thinking there is some special way to access arrays with nested objects like this, but I'm struggling to find any documentation or videos discussing it.
I can be confident the value is stored in the first array element, but methods that can search all objects would be awesome as well.
The syntax (if you know the array index - as in my initial question) is:
SELECT *
FROM topic_name
WHERE payload.foo.bar[0].id = "8177BE12-F69B-4A51-B12E-976D2AE37487"
LIMIT 10
Though I am still struggling to do this if the array index is unknown and you need to check them all. I'm assuming at this point it's not possible without a series of OR statements in the WHERE clause that checks them all.

JSON schema recursion doesnt seem to properly validate

I'm going through the docs to try and figure out how loops work so I can validate every object of an array of objects match the schema.
It seems like recursion is what I want but the example given doesn't work: https://json-schema.org/understanding-json-schema/structuring.html
I'm trying to validate that example but its always "valid". I tried changing all the field names in the JSON and it doesn't matter:
Not sure what's happening. For this example how would I validate every child matches the person schema (without statically writing out each one in the schema).
For example, I want to valid this JSON. there could be any number of objects under toplevel and any number of objects under "objectsList". I want to make sure every object under "objectsList" has the right field names and types (again without hard coding the entire thing in the schema):
{
"toplevel": {
"objectOne": {
"objectsList": [
{
"field1": 1231,
"field2": "sekfjlskjflsdf",
"field3": ["ssss","eeee"],
},
{
"field1": 11,
"field2": "sef",
"field3": ["eeee","qqqq"],
},
{
"field1": 1231,
"field2": "wwwww",
"field3": ["sisjflkssss","esdfsdeee"],
},
]
},
"objectTwo": {
"objectsList": [
{
"field1": 99999,
"field2": "yuyuyuyuyu",
"field3": ["ssssuuu","eeeeeee"],
},
{
"field1": 221,
"field2": "vesdlkfjssef",
"field3": ["ewerweeee","ddddq"],
},
]
},
}
}
What's wrong?
The problem here is not the recursion – your schema looks good.
The underlying issue is the same as here: https://stackoverflow.com/a/61038256/5127499
JSON Schema is designed for extensibility. That means it allows any kind of additional properties to be added as long as they are not conflicting with the known/expected keywords.
Solution
The solution here is to add "additionalProperties": false in your "person" (from the screenshot) and top-level schema to prevent those incorrect objects to be accepted. Same goes for your second example: in any definitions of "type": "object" you'd have to add "additionalProperties": false if you don't want to allow these extraneous properties to be defined.
Alternatively, you can declare your expected properties as required to ensure that at least those are present.
Why?
As per json-schema.org/understanding-json-schema (emphasis mine):
The additionalProperties keyword is used to control the handling of extra stuff, that is, properties whose names are not listed in the properties keyword. By default any additional properties are allowed.
The additionalProperties keyword may be either a boolean or an object. If additionalProperties is a boolean and set to false, no additional properties will be allowed.
To address the screenshot you posted and why the instance passes:
The schema is looking to find a person property, but that property doesn't exist.
The schema does not declare that person is required.
The schema does not declare requirements on undefined properties, so it will always accept the personsdfsd property with whatever value is in it, without checking it further.
So in short, your JSON data is bad and your schema doesn't have any protections against that.
Other than that, your schema looks good. It should validate that items in the children property match the person definition's subschema.

how to get dictionary same order as same i am getting from json in objective c

i am parsing json and what i get set of dictionary but after parsing it will automatically change it order. i just need same order as same i am getting from json parsing.
NOTE: i want to make one functionality which depends on dictionary order, i don't want to make it manually. so it will not need to make it every-time to do.it will help to change dynamically in future
Example:
From Json:
Section:
{
category:{},
location:{},
vehicle_type:{},
mode_type:{}
}
after convert into NSDicationary:
Section:
{
vehicle_type:{}
category:{},
location:{},
mode_type:{}
}
Thanks
Order of key:value doesn't matter for JSON, as you can directly access value with the help of key string. An dictionary does not support indexing of elements, so you can't.
Dictionaries are not ordered collections. On other hand, arrays are.
Note, if you don't have access over the json format, you got no guarantees about the order of elements, if you don't have hardcoded logic in your app.
Having said that, let's take a deeper look into your case. It happens that you have one main object in your json that is Section. What is more, you have 4 ordered properties of this object that are of specific kind of their own: 0: category; 1: location; 2: vehicle_type; 3: mode_type. So here comes the good part: just change your json to look something like this:
Section:
[
{
title: "category",
value: {}
},
{
title: "location",
value: {}
},
{
title: "vehicle_type",
value: {}
},
{
title: "mode_type",
value: {}
}
]
Having this json, you just go through the Section ordered elements, check the title of the element, and create the corresponding Object. This way you can achieve what you are after.

How do I use JSONSchema to accept any object string value, regardless of its key?

I have a system that is receiving JSON messages which contain metadata from a static analysis of a file. The names of these fields are dynamically generated from the scan and can be any valid string, but the value is always a valid string.
e.g.
{
"filename": "hello.txt",
...
"meta": {
"some file property": "any string",
"some other file property": "another string",
...
}
}
I have no way of knowing what the keys in meta will be before receiving the message, nor do I know how many keys there will be. Is there a way of capturing in a JSONSchema that it doesn't matter what keys are present, so long as their values are always strings?
I think you're looking for additionalProperties
Validation with "additionalProperties" applies only to the child
values of instance names that do not match any names in "properties",
and do not match any regular expression in "patternProperties".
The value of additionalProperties can be a JSON Schema, like so
...
"additionalProperties" : {
"type": "string"
}
...
Feel free to let me know if I've missed anything in my explanation, or ask any further questions.

What means __NSSingleObjectArrayI in Objective C? when I try to read a Json

I have this code Json format:
{
"weather": [{
"description": "clear sky",
"icon": "01n"
}],
"base": "stations",
"main": {
"temp": 285.514
},
"clouds": {
"all": 0
},
"dt": 1485792967,
"id": 1907296
}
And I want to retrive icon string (01n)
And use this code:
#property(nonatomic,strong) NSString *cityImageName;
self.cityImageName = [[dataJson valueForKey:#"weather"] valueForKey:#"icon"];
And later when I check the variable print:
<__NSSingleObjectArrayI 0x604000009890>(
01n
)
Finally how can I get the string directly? not like a __NSSingleObjectArrayI
You got caught in the Key-Value Coding Trap.
valueForKey has a special behavior. Applied to an array it returns always an array of all values for the given key.
Never use valueForKey unless you intend to use KVC. The recommended syntax is objectForKey or – preferable – key subscription and in case of the array index subscription.
In this case you want to get the value for key icon of the first item in the array for key weather.
self.cityImageName = dataJson[#"weather"][0][#"icon"];
However I would add a check if the array is not empty to avoid an out-of-range exception
NSArray *weather = dataJson[#"weather"];
if (weather && weather.count > 0) {
self.cityImageName = weather[0][#"icon"];
}
__NSSingleObjectArrayI is one of the implementations of the NSArray class cluster. It's not really important to this question other than knowing that it's an array.
The reason you're getting an array (of one element) instead of a string is because the JSON you're working with contains an array with one dictionary inside of it:
"weather": [{
"description": "clear sky",
"icon": "01n"
}],
Note: the square brackets surrounding the curly brackets.
So, when you call [dataJson valueForKey:#"weather"] you get back the object that represent this part of the JSON:
[ { "description": "clear sky", "icon": "01n" } ]
Which is in this case has been decoded as an NSArray containing one NSDictionary with two keys.
When you then call valueForKey: on that array it
Returns an array containing the results of invoking valueForKey: using key on each of the array's objects.
In other words, because [dataJson valueForKey:#"weather"] is an array of one dictionary, [[dataJson valueForKey:#"weather"] valueForKey:#"icon"] is an array of only the value for the "icon" key in that dictionary.
If the JSON you're working with always has this format, then you can get the firstObject from the array to get a hold of the first string (or nil if the array was empty).