Schematron
A short introduction to Schematron
The purpose of Schematron files and their role in Semantic Treehouse.
Useful links:
- XPath cheatsheet: https://devhints.io/xpath
- XSLT, XPath functions: https://www.w3schools.com/xml/xsl_functions.asp
- An introduction to Schematron: https://www.xml.com/pub/a/2003/11/12/schematron.html
- Schematron schema definitions: http://www.datypic.com/sc/schematron/ss.html
Schematron structure
See: http://www.datypic.com/sc/schematron/ss.html
Schema element <sch:schema>
The top-level element of a Schematron schema.
A schema consists of <sch:phase>
, <sch:pattern>
, <sch:let>
and other elements. The important elements are explained below.
Phase element <sch:phase>
A grouping of patterns, to name and declare variations in schemas, for example, to support progressive validation.
Pattern element <sch:pattern>
A set of rules giving constraints that are in some way related.
Let element <sch:let>
A declaration of a named variable.
Common pitfalls and mistakes
Rule context must be unique within a pattern
See: http://schematron.com/2018/07/the-most-common-programming-error-with-schematron/
A node (xml elements) will only match one rule per pattern: the first one that matches.
So e.g. if you have the following rules:
<pattern>
<rule id="r1" context="a"></rule>
<rule id="r2" context="b"></rule>
<rule id="r3" context="a | b"></rule>
<rule id="r4" context="*"></rule>
</pattern>
When you validate a document with element <a>
, it will only fire rule r1. Element <b>
will only fire rule r2 and any other element will fire rule r4.
If you do want element <a>
to fire rule r1, r3 and r4 you must place those rules in separate patterns, like so:
<pattern>
<rule id="r1" context="a"></rule>
<rule id="r2" context="b"></rule>
</pattern>
<pattern>
<rule id="r3" context="a | b"></rule>
</pattern>
<pattern>
<rule id="r4" context="*"></rule>
</pattern>
Choice the context right!
Selecting attributes is not possible. The context must result in zero/one/more element nodes
E.g. this is NOT possible:
<rule context="//@currencyID" >
<assert test=". = 'EUR'">The attribute currencyID must contain value 'EUR'.</assert>
</rule>
You should do this instead:
<rule context="//*[@currencyID]" >
<assert test="@currencyID = 'EUR'">The attribute currencyID must contain value 'EUR'.</assert>
</rule>