Examples Documentation Contact Downloads

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.
The validator class handles all the magic. It reads validation rules from validator.xml files that will supply it with rulesets and error definitions.

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