Comparison
XSD vs Schematron
A grammar says which elements may appear. Schematron says what they must add up to. Almost every regulated format needs both, layered.
This is the one comparison on this page where the answer is usually "both", and the reason is that the two answer different questions. XSD describes shape: which elements, in what order, how many, holding what kind of value. Schematron describes consequence: that a total equals the sum of its lines, that a delivery date does not precede its order date, that a code is only allowed when another field says so.
Neither can do the other's job. XSD has no way to compare two values in a document, because its model never looks at more than one element's content at a time. Schematron has no vocabulary of its own at all — it is a list of XPath assertions and the messages to show when they fail, and it will happily approve a document whose structure is nonsense as long as no rule fires.
That is why every serious profile ships both: UBL and Peppol for invoicing, ISO 20022 usage guidelines for payments, HL7 implementation guides for clinical documents. The XSD is the contract's shape and the Schematron is its conditions, and a document that passes only one of them will be rejected by the counterparty that checks the other.
The demonstrations below run the same invoice through each. It is schema-valid and arithmetically wrong, which is exactly the document that reaches production.
What actually differs
| Aspect | XSD | Schematron |
|---|---|---|
| Standard | W3C Recommendation | ISO/IEC 19757-3 |
| Describes | Structure and datatypes | Conditions between values |
| Sees | One element's content at a time | The whole document, through XPath |
| Defines a vocabulary | Yes — this is the element list | No — it asserts about whatever is there |
| Cross-field rules | Not expressible | The entire purpose |
| Error messages | Generated by the validator | Written by whoever wrote the rule |
| Severity | Everything is an error | Roles distinguish an error from a warning |
| Code generation | A whole ecosystem | None, and none intended |
Shown, not asserted
The differences above are claims, so here they are being made. Every one of these runs on each test run, against the same engines the tools use — the outputs are what came back, not what we expected.
The invoice against its XSD: valid. Every element is where the grammar says it should be.
document.xml <?xml version="1.0"?> <invoice> <line><amount>30.00</amount></line> <line><amount>60.00</amount></line> <total>100.00</total> </invoice>schema.xsd <?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="invoice"> <xs:complexType> <xs:sequence> <xs:element name="line" maxOccurs="unbounded"> <xs:complexType><xs:sequence> <xs:element name="amount" type="xs:decimal"/> </xs:sequence></xs:complexType> </xs:element> <xs:element name="total" type="xs:decimal"/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>What came back
Valid against the XSD grammar above.The same invoice against one Schematron rule: the total is wrong, and it says so in the words whoever wrote the rule chose.
document.xml <?xml version="1.0"?> <invoice> <line><amount>30.00</amount></line> <line><amount>60.00</amount></line> <total>100.00</total> </invoice>rules.sch <?xml version="1.0"?> <schema xmlns="http://purl.oclc.org/dsdl/schematron"> <pattern> <rule context="invoice"> <assert test="total = sum(line/amount)">The total must equal the sum of the line amounts.</assert> </rule> </pattern> </schema>What came back
An assertion failed, in the words the rule's author wrote.The total must equal the sum of the line amounts.Correct the total and the same rule passes. Nothing about the structure changed — only the arithmetic.
document.xml <?xml version="1.0"?> <invoice> <line><amount>30.00</amount></line> <line><amount>60.00</amount></line> <total>90.00</total> </invoice>rules.sch <?xml version="1.0"?> <schema xmlns="http://purl.oclc.org/dsdl/schematron"> <pattern> <rule context="invoice"> <assert test="total = sum(line/amount)">The total must equal the sum of the line amounts.</assert> </rule> </pattern> </schema>What came back
Every assertion holds.And the reverse: a document XSD would reject outright passes every rule, because no rule asked about structure.
document.xml <?xml version="1.0"?> <invoice><nonsense/></invoice>rules.sch <?xml version="1.0"?> <schema xmlns="http://purl.oclc.org/dsdl/schematron"> <pattern> <rule context="line"> <assert test="amount">A line must carry an amount.</assert> </rule> </pattern> </schema>What came back
Every assertion holds.
Which to pick
XSD, when
- You are defining the vocabulary itself — what the elements are and what may nest inside what.
- Values need type checking: dates, decimals with a fixed scale, enumerations, patterns.
- Something downstream generates code from the schema, which is XSD's world entirely.
Schematron, when
- The rule involves more than one value — a total, a date ordering, a field that is required only when another is present.
- The failure message has to be readable by whoever has to fix the document, rather than by whoever wrote the schema.
- A counterparty publishes rules on top of a schema you do not control, which is how every e-invoicing and payments profile works.
Where it reaches
- ToolsSchematron validatorRun your own rules against your own document, with the engine these demonstrations use.
- ToolsXSD validatorThe other half of the pair: check the structure before checking the conditions.
- FormatsUBL InvoiceThe format that made this layering mainstream — an XSD with a Schematron profile on top.
Related comparisons
- XSD vs RELAX NGXSD has the type system and RELAX NG has the grammar. Which matters more depends on whether your documents are records or prose.
- XSD vs DTDDTDs came with XML and are still the only way to declare an entity. For everything else XSD replaced them — and this is the one comparison we cannot run.
Get started
Bring order to the XML your team can't afford to ignore.
Create a free account and get a private workspace to search, validate, diff, and monitor your XML feeds, sitemaps, schemas, and vendor integrations.