Data Validation
All this reading about schemas may have made you wonder about validation. For most XML schema languages, it's what the schema is there for to begin with. Within grace, validation is handled by an entirely different class and as a separate step from data translation. The potentially complex wrapping and mangling happening in the translation schemas implemented by the xmlschema class make its schema language less suitable for defining data restraints. For that reason, grace defines the separate validator class that acts upon the native, in-memory representation. A side-effect of this approach is that software using these classes is more liberal in what it will accept from the outside and more strict in what it emits, which is how the internet likes things. The validation process involves itself with a number of restraints that you would want to place on your data:
- Defining mandatory and optional child keys and attributes.
- Verifying mandatory dependencies resulting from optional child keys and attributes.
- Checking the actual data against validation criteria.
match.data
match.id
match.child
match.rule
match.attrib
match.mandatory
mandatory
optional
Using the validator Class
The validator class uses its own schema language. Such a validation schema can best be seen as a language controlling both iteration over a tree of data and validation of members, attributes and data. As a first example, we will look at a simple record type:
<?xml version="1.0"?>
<dict>
<string id="username">john428</string>
<integer id="maxtimeout">80</integer>
<string id="accounttype">user</string>
</dict>
A possible validation schema for such a record could look like this:
<?xml version="1.0"?>
<grace.validator>
<datarule id="root">
<match.mandatory>
<mandatory type="child" key="username"/>
<mandatory type="child" key="maxtimeout"/>
<mandatory type="child" key="accounttype"/>
</match.mandatory>
<match.child>
<and>
<match.id>username</match.id>
<match.rule>username</match.rule>
</and>
<and>
<match.id>maxtimeout</match.id>
<match.rule>maxtimeout</match.rule>
</and>
<and>
<match.id>accounttype</match.id>
<match.rule>accounttype</match.rule>
</and>
</match.child>
<datarule>
<datarule id="username">
<match.data errorcode="101" errortext="Invalid username">
<regexp>[[:alnum:]]{2,8}</regexp>
</match.data>
</datarule>
<datarule id="maxtimeout">
<match.data errorcode="102" errortext="Timeout too high">
<lt>3600</lt>
</match.data>
<match.data errorcode="103" errortext="Timeout too low">
<gt>60</gt>
</match.data>
</datarule>
<datarule id="accounttype">
<match.data errorcode="104" errortext="Invalid accounttype">
<text>user</text>
<text>moderator</text>
<text>administrator</text>
</match.data>
</datarule>
</grace.validator>
As you can see, the <grace.validator> class contains a list of <datarule> objects that can be seen as the validation rules for a single data node. All the child nodes of a given <datarule> object define a criterium and the node is only considered valid if all of them report a positive result. A <match.mandatory> criterium defines a list of mandatory children and/or attributes. If a <mandatory> status is defined for a child or attribute, its absence in the data node will trigger a failure. You can also flag a child or attribute with an <optional> object, which itself can contain one or more <optional> and <mandatory> objects to handle optional objects that trigger mandatory dependencies.
A <match.child> criterium triggers an iteration over all of the data node's child object. The criterium will be evaluated as valid as long as one of the matches is succesful. You can use <and> as well as <or> objects to group together certain conditions. Any of the other matchtypes is also allowed within this context. The <match.rule> object, for instance, is just a command to jump to evaluating the current match against a different <datarule> object. There's nothing stopping you from using these rules inline.
Underneath you will find an overview of the objects involved with the validator schemas, including their attributes and possible child objects.
match.data
Match the object's data against a list of criteria. The child nodes are combined with a logical OR, implying that a minimum of one of the child criteria must match for the data to be considered valid.
If you have a need for multiple data criteria lists to match against you can use the <and>> object to combine multiple <match.data> segments.
| Attributes | |
|---|---|
| errorcode | Error code to return if object data does not match against the criteria. |
| errortext | Error text to return if validation failed. |
| Children | |
| <text> | Match against a literal text string |
| <regexp> | Match against a regular expression |
| <lt> | Match if integer value of data is less than provided value |
| <gt> | Match if integer value of data is less than provided value |
| <minsz> | Match minimum string size |
| <maxsz> | Match maximum string size |
match.id
Match the object's key to a value
| Attributes | |
|---|---|
| errorcode | Error code to return if object data does not match against the criteria. |
| errortext | Error text to return if validation failed. |
| Children | |
| [CDATA] | The matching key |
match.child
Match every child object against a set of rules. The rules are combined with a logical OR, where the validation succeeds if at least one of the child objects returns a positive result.
| Attributes | |
|---|---|
| errorcode | Error code to return if object data does not match against the criteria. |
| errortext | Error text to return if validation failed. |
| Children | |
| <and> | Perform a logical AND on a chain of child rules |
| <match.id> | Match a key |
| <match.rule> | Perform a match for the child object against a <datarule> |
| <match.data> | Perform a match against the child's data |
| <match.attrib> | Perform a match against the child's attributes |
| <match.child> | Perform a match against the child's children. |
| <match.mandatory> | Perform a match against the child's mandatory child keys and attributes |
match.rule
Match object against another <datarule> set.
| Children | |
|---|---|
| [CDATA] | The matching key |
match.attrib
Match every attribute against a set of rules. The rules re combined with a logcal OR, where the validation succeeds if at least one of this rule's child rules yields positive result.
| Attributes | |
|---|---|
| errorcode | Error code to return if object data does not match against the criteria. |
| errortext | Error text to return if validation failed. |
| Children | |
| <and> | Perform a logical AND on a chain of child rules |
| <match.id> | Match a key |
| <match.data> | Perform a match against the child's data |
match.mandatory
Match mandatory sub-objects or optionals with mandatory dependencies.
| Children | |
|---|---|
| <mandatory> | Match a mandatory sub-object |
| <optional> | Match an optional sub-object |
mandatory
Define a mndatory child object or object attribute with its key.
| Attributes | |
|---|---|
| type | Either "child" or "attrib" |
| key | The key of the mandatory child or attribute |
| errorcode | Error code to return if object does not match against the criteria |
| errortext | Error text to return if validation failed |
optional
Define an optional child object or object attribute, with depending sub-rules.
| Children | |
|---|---|
| <optional> | Depending optional rule |
| <mandatory> | Depending mandatory rule |
| Attributes | |
| type | Either "child" or "attrib" |
| key | The key of the optional child or attribute |
| Previous Chapter | Table of Contents | Next Chapter |