Validation Object - Gnof/JsonValidator GitHub Wiki
The Json Validator takes in a JSON following this specific format:
[
{
attribute:'foo',
value:'bar',
quantity: 1,
hierarchy: [[parent, node]],
ancestor: [parent],
composite: [{... some validator object }]
}
]
Passing in a (valid) validation object to the JsonValidator as well as a target JSON to validate it against will return you a boolean result. However, since you may want to know exactly what's going on with it in a programmatic way, it also returns to you a detailed result object for you to peruse.
Notice that you can pass in a LIST of validation objects, as the resulting validation will return a hash of results for each one.
* - unless otherwise specified, the attributes specified are optional
attribute (string) - (REQUIRED): The attribute you are searching for in the JSON
value (string | list): A specific value you are searching for in the JSON that belongs to the specified attribute. Value can be a single value string like 'bar'. It can also be a JSON array of strings, like:
...
value: ["bar", "boom", "blam"],
...
If a list is specified, the validation will only pass if all values are present in multiple objects in the target JSON. Because of this, it's assumed there are multiple object instances within the scope of a larger object containing the same attribute. Also, if you are verifying the 'quantity' criteria, the number of values should be less than or equal to the quantity expected, or it will always fail for obvious reasons.
quantity (int): The number of instances we expect to see this attribute in the target JSON to verify. As JSON keys are meant to be unique, this verification is meant for JSON objects that contain multiple instances of another JSON object. For example:
{
"value1":
{
"status":false,
"cause":"service"
},
"value2":
{
"status":true,
"cause":"device"
}
}
We can specify:
{
attribute:"status",
quantity: 2
...
}
to check whether there are 2 instances of a "status" node.
hierarchy(list(list)): The path to the attribute you're looking for, from the root attribute to the one you're looking for. This is specified as a list of a list of strings so that you can validate multiple paths in the same validation. For example, given this target JSON to validate:
{"properties":[
{"foo":"bar"},
{"foo":"bat"},
{"wah":
{"foo":"blam"}
}
]}
We may want to verify that 'foo' has a hierarchy of 'properties', and we would do it like this:
{attribute:"foo",
hierarchy:[["properties"]]
}
The above validation would be 'true' for the previous JSON example because both {"foo": "bar"}, and {"foo": "bat"} are both direct children of the "properties" attribute.
We can also verify the longer path, which is where this is useful:
{attribute: "foo",
hierarchy:[["properties", "wah"]]
}
The above validation would be 'true' as well because {"foo":"blam"} is a child of "wah", which belongs to "properties". Keep in mind that order matters (i.e. "wah", "properties" will fail) If you are just looking for the existence of ancestors and not the path to the attribute, use the 'ancestor' validation attribute.
You can also specify multiple hierarchies:
{attribute: "foo",
hierarchy:[["properties", "wah"], ["properties"]]
}
This above validation will pass because both hierarchies exist like in the previous two examples, and this shows they can be done at the same time.
Also keep in mind that when using the hierarchy attribute with the 'value' attribute, the validation is done against the hierarchy found for the attribute / value PAIR.
{attribute: "foo",
value: "blam",
hierarchy:[["properties", "wah"]]
}
The above validation will pass, because {"foo":"blam"} is specifically the child of "properties" -> "wah". However:
{attribute: "foo",
value: "bar",
hierarchy:[["properties", "wah"]]
}
Will FAIL because {"foo":"bar"} is the child of "properties", and not "properties" -> "wah"
ancestor(string, list): A single string or list of (unordered) strings specifying the ancestors you are expecting for the specified attribute in the validation.
For example, in the following JSON:
{"properties":[
{"foo":"bar"},
{"foo":"bat"},
{"wah":
{"foo":"blam"}
}
]}
The following validation specifies that I want to verify that 'foo' has an ancestor 'wah':
{attribute: "foo",
ancestor: "wah"
}
The above validation will pass because {"foo": "blam"} has the ancestor "wah".
We can also specify a list like so:
{attribute: "foo",
ancestor: ["wah", "properties"]
}
The above validation will pass because for ALL the JSON objects that have "foo" as an attribute, "properties" and "wah" both occur in their hierarchies. Note that this is an unordered list.
When using the "ancestor" validation attribute with the "value" attribute, we will look specifically for the context where the attribute / value pair exist.
{attribute: "foo",
value: "blam"
ancestor: "wah"
}
The above validation will PASS because "wah" is an ancestor of the {'foo': 'blam'} object. However...
{attribute: "foo",
value: "bat",
ancestor: "wah"
}
will FAIL because {"foo":"bat"} only has the ancestor "properties".
composite:(validation object | list) Composite is a neat verification in that in allows you to pass a composite key in addition to your validation criteria. Composite takes in either a validation object, or a list of validation objects and performs validations against the same target JSON, except that the overall validation is done AFTER the criteria of the composite validations have been done.
Here's a simple example of how to use composite:
{"properties":[
{"foo":"bar",
"comp1":"key1",
"comp3":"key2"
},
{"comp2":"key2",
"foo":"bat"
},
{"wah":
{"foo":"blam"}
}
]}
If I want to verify that "foo" exists, with a value "bar" within the SAME object as "comp1" with value "key1":
{attribute: "foo",
value: "bar",
composite: {attribute:"comp1", value:"key1"}
}
The above validation will pass, since the object: {"foo": "bar", "comp1":"key1"...} exists.
We can also do everything in the composite validation that we do in the regular validation object:
{attribute: "foo",
value: "bar",
composite: {attribute:"comp1", value:"key1", hierarchy: [["properties"]]}
}
The above validation will pass because the composite validation {"attribute:"comp1"...} exists and returns to the main validation the context {"foo":"bar", "comp1":"key1"...}, which then passes the main validation that "foo":"bar" exist.
However:
{attribute: "foo",
value: "bar",
composite: {attribute:"comp2", value:"no"}
}
The above validation will FAIL because the composite validation passes (since {"comp2":"no", "foo":"bat"} exists), but that context FAILS the main validation of "foo":"bar" ("foo":"bat" is found instead).
You can also list validation objects to pass the composite check:
{attribute: "foo",
value: "bar",
composite: [{attribute:"comp1", value:"key1"}, {attribute:"comp3", value:"key2"}]
}
The above validation passes because {"foo":"bar", "comp1":"key1","comp3":"key2"} meets the criteria of the composite keys individually, returning the context to the main validator which then passes the "foo":"bar" validation.