XML Tutorial · Validation · Lesson 11 of 28

RELAX NG and Schematron

RELAX NG as a simpler grammar-based schema language, and Schematron for business rules that grammars can't express.

Create a free account to save this page, take notes and track your progress. Sign in

RELAX NG

RELAX NG (ISO/IEC 19757-2) describes the same structures as XSD with a much smaller, more readable language. It has an XML syntax and a compact syntax:

element order {
  attribute id { xsd:integer },
  element customer { text },
  element item { attribute qty { xsd:positiveInteger }, text }+
}

It's used by DocBook, the TEI, OpenDocument (ODF) and EPUB. libxml2 (lxml, PHP's relaxNGValidateSource) and Jing validate it.

Validate with RELAX NGTry it yourself
from lxml import etree

rng = etree.RelaxNG(etree.fromstring(b"""
<element name="order" xmlns="http://relaxng.org/ns/structure/1.0"
         datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
  <attribute name="id"><data type="integer"/></attribute>
  <element name="customer"><text/></element>
  <oneOrMore>
    <element name="item">
      <attribute name="qty"><data type="positiveInteger"/></attribute>
      <text/>
    </element>
  </oneOrMore>
</element>"""))

for xml in (b'<order id="1"><customer>Ada</customer><item qty="2">Tea</item></order>',
            b'<order id="1"><customer>Ada</customer></order>'):
    doc = etree.fromstring(xml)
    print("valid" if rng.validate(doc) else f"invalid: {rng.error_log.last_error.message}")

Output

valid
invalid: Expecting an element , got nothing

Schematron: rules, not grammar

Grammars say what structure is allowed. Schematron (ISO/IEC 19757-3) states rules as XPath assertions, with human-readable messages. It's ideal for business rules such as "the total must equal the sum of the lines" or "a delivery date can't be before the order date":

Business rules with SchematronTry it yourself
from lxml import etree, isoschematron

rules = isoschematron.Schematron(etree.fromstring(b"""
<schema xmlns="http://purl.oclc.org/dsdl/schematron">
  <pattern>
    <rule context="invoice">
      <assert test="number(total) = sum(line/@amount)">The total must equal the sum of the lines.</assert>
      <assert test="due &gt;= issued">The due date can't be before the issue date.</assert>
    </rule>
  </pattern>
</schema>"""), store_report=True)

invoice = etree.fromstring(b"""<invoice>
  <issued>20261101</issued><due>20261020</due>
  <line amount="30"/><line amount="12.5"/>
  <total>40</total>
</invoice>""")
print("valid:", rules.validate(invoice))
for failed in rules.validation_report.iter("{http://purl.oclc.org/dsdl/svrl}failed-assert"):
    print("-", failed.findtext("{http://purl.oclc.org/dsdl/svrl}text").strip())

Output

valid: False
- The total must equal the sum of the lines.
- The due date can't be before the issue date.

A common setup is XSD (or RELAX NG) for structure plus Schematron for business rules. Electronic invoicing in the EU (EN 16931) is validated exactly this way.

Test yourself

Which schema language is best for a rule like 'total equals the sum of line amounts'?

  1. Schematron
  2. DTD
  3. XSD 1.0 without extensions
  4. RELAX NG compact syntax
Show answer

Answer: Schematron

Schematron asserts arbitrary XPath conditions; grammar-based languages describe structure and types.

Was this page helpful?