In the previous sections, we have seen two different ways of validating the content of an XML file: while DTDs can only validate the element nesting structure, XML and RELAX NG schemas can also validate the content of the elements by enforcing local constraints such as the length of strings, regular expressions or range on the allowed values. These types of constraints, defined by means of grammars described the well-formedness of structure and values, can be characterized as syntactic. But in typical applications, more semantic types of constraints could be appropriate for checking long distance dependencies that would be awkward or even impossible to express by means of grammar rules or regular expressions, e.g. a starting date in an attribute or element should be earlier than an ending date in another one. In this case, a rule-based approach is more appropriate.
Typical global semantic constraints can be defined to take into account relations between elements and attributes: for example, an attribute with a given value could imply the definition of another element. It could be necessary that a certain value is equal to the sum of other values. In certain cases, it would even be interesting to enforce constraints between different XML files. These checks are outside the scope of the XML validation methods we have presented in the previous sections, but an alternative approach, called Schematron [20], [86] has been developed to cope with this type of validation. Instead being grammar-based, Schematron is a rule-based validation approach to define assertions in which XPath expressions are evaluated. XPath expressions will be described more fully in Chapter 4, but for the moment they can understood as defining values computed over different parts of an XML file; in fact, Schematron even allows combining values spanning more than one XML file. In principle, Schematron could be used for also defining local constraints, but as they are much more easily defined by grammars, we will use Schematron patterns as supplementary validation rules used in conjunction with an XML Schema. The Schematron specification describes how patterns can be embedded within other XML schema notations such as XML Schema, RELAX NG and RELAX NG Compact.
Similarly to an XML Schema and RELAX NG file, a Schematron file is a well-formed
(and valid) XML file that defines validation in terms of pattern
elements
containing rule
elements. A rule
defines a context for internal XPath
expressions used in assertion
and report
elements. When the
XPath expression of an assertion
(resp. report
) is false
(resp. true
), then the content of the element is output as validation message.
The validation message can contain variable parts to customize the message according to the
context and the specific elements involved.
Typical semantic validation uses are the following:
Example 3.8 shows Schematron rules for the cellar book. These rules should be combined with the XML Schema or RELAX NG in order to validate the instance file both syntactically and semantically. We use the ISO Schematron [67] that has been recently standardised,. It differs in some respects from the Schematron 1.6 dialect [87], but the main ideas remain valid in both formalisms.
Table 3.4 presents the XML elements we use in our example to define the types needed for the validation of our wine catalog and cellar book.
Table 3.4. Schematron syntax reminder
<schema targetNameSpace="URI"> title? ns? pattern+ </schema> |
<ns prefix="QName" uri="URI"/> |
<title> PCDATA </title> |
<pattern abstract="yes | no" id="ID" is-a="IDREF"> param* rule+ </pattern> |
<param name="QName" value="XPathExpr"/> |
<rule context="XPathExpr"> {let | report | assert}* </rule> |
<let name="QName" value="XPathExpr"/> |
<report test="XPathExpr"> {PCDATA | value-of | name}* </report> |
<assert test="XPathExpr"> {PCDATA |value-of | name}* </assert> |
<value-of select="XPathExpr"/> |
<name/> |
A reminder of the subset of the Schematron syntax used in Example 3.8. Names in italics
refer to other elements. PCDATA
refers to XML string content .
Regular expressions (see Table B.1) are used to describe the allowed forms.
Example 3.8. [CellarBook.sch
] ISO-Schematron for the cellar book to validate
Example 2.2.
This file can be used in combination with the XML Schema shown in Example 3.3.
1 <?xml version="1.0" encoding="UTF-8"?> <schema xmlns="http://purl.oclc.org/dsdl/schematron"xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
queryBinding="xslt2"> 5 <title>Validation using Schematron rules</title>
<ns prefix="cat"
uri="http://www.iro.umontreal.ca/lapalme/wine-catalog"/> <xsl:key name="colors" match="/cellar-book/cat:wine-catalog/cat:wine"
use="cat:properties/cat:color"/> 10 <pattern>
<rule context="wine"> <report test="rating/@stars>1 and not(comment)"> There should be a comment for a wine with more than one star. 15 </report> </rule> </pattern> <pattern>
20 <rule context="cellar"> <let name="nbBottles" value="sum(wine/quantity)"/>
<report test="$nbBottles < 10"> Only <value-of select="$nbBottles"/> bottles left in the cellar. </report> 25 <!-- nb of bottles of each color in the cellar --> <let name="winesFromCellar" value="/cellar-book/cellar/wine"/>
<let name="nbReds" value="sum($winesFromCellar[@code=key('colors','red')/@code]/quantity)"/> <let name="nbWhites" 30 value="sum($winesFromCellar[@code=key('colors','white')/@code]/quantity)"/> <let name="nbRosés" value="sum($winesFromCellar[@code=key('colors','rosé')/@code]/quantity)"/> <let name="nbColors" value="$nbReds+$nbWhites+$nbRosés"/> <!-- check for a well balanced cellar!!! --> 35 <assert test="$nbReds>$nbColors div 3"> Not enough reds (<value-of select="$nbReds"/> over <value-of select="$nbColors"/>) left in the cellar. </assert> <assert test="$nbWhites>$nbColors div 4"> 40 Not enough whites (<value-of select="$nbWhites"/> over <value-of select="$nbColors"/>) left in the cellar. </assert> <assert test="$nbRosés>$nbColors div 4"> Not enough rosés (<value-of select="$nbRosés"/> over 45 <value-of select="$nbColors"/>) left in the cellar. </assert> <!-- check for consistency within number of bottles --> <assert test="$nbBottles=$nbColors">
Inconsistent count of bottles: total is <value-of select="$nbBottles"/> 50 but the count by colors is <value-of select="$nbColors"/>: (<value-of select="$nbReds"/> reds, <value-of select="$nbWhites"/> whites and <value-of select="$nbRosés"/> rosés). </assert> </rule> 55 </pattern> <pattern abstract="true" id="spacesAtStartEnd">
<rule context="comment|cat:comment|cat:food-pairing|cat:tasting-note"> <report test="starts-with($elem,' ') or 60 substring($elem,string-length($elem))=' '"> A <value-of select="name($elem)"/> element within a <name/> should not start or end with a space. </report> </rule> 65 </pattern> <pattern is-a="spacesAtStartEnd">
<param name="elem" value="cat:bold"/> </pattern> <pattern is-a="spacesAtStartEnd">
70 <param name="elem" value="cat:emph"/> </pattern> </schema>
|
ISO-Schematron rules are defined within an XML element defined in a
specific namespace. We also declare the |
|
By setting |
|
Gives an informative title to a set of validation rules. |
|
Defines the namespace prefix to be used within XPath expressions
that refer to elements of the wine catalog (see line 8‑ |
|
Declares that |
|
Defines a cooccurrence constraint within a
|
|
A pattern that defines a rule implementing a mix of cooccurrence
and algorithmic constraint within a |
|
There should be a warning when the total number of bottles in the cellar is less
than 10.
This is obtained by summing the values of all the |
|
Defines a mix of cooccurrence and algorithmic constraints by computing
the total number of bottles of each color and asserting that there should be at
least a third of the number of bottles that are red, one fourth of both rosés
and whites. The codes of wines of a given color are found by searching with the
|
|
Checks that the total number of bottles in the cellar is equal to the sum of the numbers of each color. This an internal consistency check which in principle should never appear because it would mean that there a wines that are not red, white or rosé. But these values are the only ones allowed by the XML Schema |
|
Defines an abstract pattern for
generating two other patterns (line 66‑ |
|
Instantiates the abstract pattern defined at line 57‑ |
|
Instantiates the abstract pattern defined at line 57‑ |
This example shows how new kinds of validation rules can be applied. The main advantages being the possibility of enforcing long-distance or algorithmic dependencies that cannot be implemented by the grammar-based validation offered by DTD and XML Schemas. Another advantage is the possibility of giving more meaningful error messages for the user than the ones generated automatically by a grammar based validation. As these validations are enforced by run-time checking once the user has entered the values in the file, it is not possible to determine a list of allowed choices that can be displayed by an XML editor at any point in the file. Although the ISO specification is relatively short (about 20 pages), we have not covered here all aspects of Schematron. In particular, we have not described the order of evaluation of the patterns and rules and we omitted some elements that are used for formatting and organizing processing phases and diagnostic messages, even multi-lingual ones.
In principle, Schematron could be used as the sole validation mechanism for XML instance
files but simple sequencing constraints that are easy to express in a grammar must rely on
complex XPath expressions involving ::following-sibling[1]
. So in
practice, it is more convenient to use both types of validation.
But if having two separate validation files
is not suitable, it is possible to embed Schematron rules within xs:appinfo
and xs:annotation
elements of an XML Schema. Similar embedding conventions have
be defined for both RELAX NG and RELAX NG Compact.