If you use XML schema languages, you should consider Schematron. This powerful rule-based language lets you make distinctions which other languages find difficult or even impossible to handle. Best of all, you can use it in conjunction with other schema languages. This is the first part of a three-part series.
Using Schematron - Making assertions (Page 3 of 4 )
We'll start at the "bottom" of Schematron and then make our way up until we have arrived at a complete schema definition. The simplest unit in Schematron is an assertion. An assertion in Schematron is actually written out in plain language. Earlier, we made an assertion dealing with a resident's age and eligibility to vote: "If the resident's age is below 18, then the resident should not be able to vote." Taken as-is, this, of course, will do nothing. While an assertion is written out in plain language, it must also contain an XPath expression to back it up. This expression makes up the assertion test. The assertion test for our voter eligibility assertion would look like this:
(age < 18 and eligible_to_vote = 'no') or age > 18
Above, either the voter is under eighteen and not able to vote, or the voter is over eighteen. Any under condition will result in the XPath expression evaluating to false, which will cause the assertion to be unmet and the document not to validate.
So, how would this look in a schema definition? Let's get to the actual markup used to create this assertion:
<asserttest="(age < 18 and eligible_to_vote = 'no') or age > 18">
If the resident's age is below 18, then the resident should not be able to vote.
Above, you can make out the assertion, which makes up the inner content of the assert tag, and the assertion test, which is contained in the test attribute.
The assertion we made demonstrates how a value contained in one element can affect the validity of a value contained in another element. This assertion demonstrates one of Schematron's greatest strengths: it can define validity in complex ways. We can, of course, keep adding assertions for a more complex result. For example, we could bring in other factors that affect a person's eligibility to vote, such as whether or not a resident is even a citizen. This would create yet another relationship for which to test.
Let's go ahead and create the relevant assertion for this. A status tag could be added with two possible values: "alien" and "citizen." The assertion should read, "Aliens cannot vote." The complete markup would look like this:
<asserttest="(status = 'alien' and eligible_to_vote = 'no') or status = 'citizen'">
Aliens cannot vote.
Assertions don't have to be complex, though. They can also be very simple. For example, we could create an assertion to check for the mere presence of an element. Let's check to make sure that each resident element has an age element, a status element, and an eligible_to_vote element: