At the moment, include and extends are defined in ways that allow simple textual operations (simple macro-expansion) rather than "semantic" operations: it requires consideration neither of the included contents nor the position the inclusion takes place.
In particular, because of sch:ns, there is no need to trace through elements to reconcile which namespace declarations are in-scope. Similarly, because sch:ns is only found at the /sch:schema/* level, like sch:pattern and in-scope sch:let, there is no need to look at contexts etc to find contexts.
When a schema A extends another schema B, it in effect overrides Schema B's /sch:schema/@* because they are simply not imported.
Errors are found at runtime, if triggered. The trade-offs between scripting (e.g. runtime error detection) and static compilation (e.g. compile-time error detection) are well-rehearsed, and appropriate in different situations. In XSD's case, because it was designed to drive or respond to the type systems of large programming languages, static type-checking of the XSD schemas is entirely appropriate, IMHO.
Characterization
I think Schematron's sch:extend's and sch:include's simplicity is a strength for implementators and ease of understanding, and contrasts with the complexity and lack of bang-per-buck of XSD's mechanisms. But I think it is skewed to modularity (to divide a large schema into smaller parts) rather than construction (making a new schema from parts) or abstraction (exposing some pattern in the schema that is conceptually useful.)
Nevertheless, it would be possible to keep the inclusion model and add a measure of include-time errors or warnings.
Examples
Lets look at some kind of easily-detectable potential failure situations. Lets say schema A extends schema B at the top level
there are duplicate but incompatible declarations for the same named sch:ns, sch:param, sch:phase
there are duplicate named sch:let and sch:pattern
the QLB for schema B requires xslt3 but schema A wants to limit to xslt2
the default phase for schema A could be different than the default phase for schema B.
I would say that we are missing a good or clear system (unless this has changed??) of overriding.
Suggestion: If schema A extends schema B (i.e. B's /sch:schema/sch:* are notionally included into A's /sch:schema ) then
Overriding Schematron elements
any declarations in A /sch:schema/sch: and /sch:schema/xslt: that have the same name element name and identifier as some element in B should cause the declaration in B to be suppressed and not imported, and an optional INFO generated about this override;
if the sch:ns, sch:param, or sch:let have the same textual value, no INFO needs to be generated as the override cannot be semantically significant.
Overriding sch:schema attributes
if an /sch:schema/@* defined by Schematron is different between schema A and B, then in the absence of hardcoded heuristics it should generate a WARN or ERROR
if an /sch:schema/@* defined by Schematron is different between schema A and B, and the compatibility relationship is known (by the implementation) then the implementation can provide other options. E.g. if schema A has a QLB of "xpath2" and extended schema B has a QLB of "xpath3" then this should generate some user notification, e.g. ERROR or FAIL that there could be an incompatability, or it could automatically take the schema B value and WARN or INFO the user, or it could leave it for a potential runtime fail, or it could employ some deeper validation. Alternatively, in the reverse case, the implementation could decide the xpath2 is an adequate subset of xpath3 and ignore the difference, so Schema A's QLB of xpath3 is kept.
Overriding xmlns namespace declarations
When importing or extending a schema, the in-scope namespace declarations for the elements in schema B need to be brought into schema A on the elements being imported or included. This does not affect XPaths, but:
schemas that use a different prefix for schematron schema elements (e.g. "sch" versus "iso" versus default)
sch:property elements whose contents are in some foreign namespace
xslt function definitions which have prefixed function names, and these prefixes are defined in the schema using xmlns. (We can assume that namespace defined using sch:ns are available, yes?)
Status quo
At the moment, include and extends are defined in ways that allow simple textual operations (simple macro-expansion) rather than "semantic" operations: it requires consideration neither of the included contents nor the position the inclusion takes place.
In particular, because of sch:ns, there is no need to trace through elements to reconcile which namespace declarations are in-scope. Similarly, because sch:ns is only found at the /sch:schema/* level, like sch:pattern and in-scope sch:let, there is no need to look at contexts etc to find contexts.
When a schema A extends another schema B, it in effect overrides Schema B's /sch:schema/@* because they are simply not imported.
Errors are found at runtime, if triggered. The trade-offs between scripting (e.g. runtime error detection) and static compilation (e.g. compile-time error detection) are well-rehearsed, and appropriate in different situations. In XSD's case, because it was designed to drive or respond to the type systems of large programming languages, static type-checking of the XSD schemas is entirely appropriate, IMHO.
Characterization I think Schematron's sch:extend's and sch:include's simplicity is a strength for implementators and ease of understanding, and contrasts with the complexity and lack of bang-per-buck of XSD's mechanisms. But I think it is skewed to modularity (to divide a large schema into smaller parts) rather than construction (making a new schema from parts) or abstraction (exposing some pattern in the schema that is conceptually useful.)
Nevertheless, it would be possible to keep the inclusion model and add a measure of include-time errors or warnings.
Examples Lets look at some kind of easily-detectable potential failure situations. Lets say schema A extends schema B at the top level
I would say that we are missing a good or clear system (unless this has changed??) of overriding.
Suggestion: If schema A extends schema B (i.e. B's /sch:schema/sch:* are notionally included into A's /sch:schema ) then
Overriding Schematron elements
any declarations in A /sch:schema/sch: and /sch:schema/xslt: that have the same name element name and identifier as some element in B should cause the declaration in B to be suppressed and not imported, and an optional INFO generated about this override;
if the sch:ns, sch:param, or sch:let have the same textual value, no INFO needs to be generated as the override cannot be semantically significant.
Overriding sch:schema attributes
if an /sch:schema/@* defined by Schematron is different between schema A and B, then in the absence of hardcoded heuristics it should generate a WARN or ERROR
if an /sch:schema/@* defined by Schematron is different between schema A and B, and the compatibility relationship is known (by the implementation) then the implementation can provide other options. E.g. if schema A has a QLB of "xpath2" and extended schema B has a QLB of "xpath3" then this should generate some user notification, e.g. ERROR or FAIL that there could be an incompatability, or it could automatically take the schema B value and WARN or INFO the user, or it could leave it for a potential runtime fail, or it could employ some deeper validation. Alternatively, in the reverse case, the implementation could decide the xpath2 is an adequate subset of xpath3 and ignore the difference, so Schema A's QLB of xpath3 is kept.
Overriding xmlns namespace declarations
When importing or extending a schema, the in-scope namespace declarations for the elements in schema B need to be brought into schema A on the elements being imported or included. This does not affect XPaths, but:
Rick