Re: multiply-connected graph of schema import

> The text of 1.0 defines inclusion in terms of 'the schema corresponding
> to' the included schema document, and its effect on 'the schema
> corresponding to' the including schema document.  So if A includes
> B, we can know what schema corresponds to A only by first calculating
> the schema corresponding to B.  In the case of circular includes, the
> schema corresponding to Be can be calculated only by first
> calculating the schema corresponding to A.  But we do not yet
> know what that is, because we have not yet calculated all the
> things it depends on.  We have infinite regress, caused by
> a recursive definition that identifies no base case.
>
> The most natural implementation of this definition is to turn the
> circular case into an infinite loop, and that is in fact what some
> implementations have done.  Other implementations of XSD 1.0
> have taken the view that circular includes are legal and have a
> well defined meaning, but I do not know how they derive that
> conclusion from the text of the spec

Well, yes, when I was implementing it I struggled with this, and I made 
circular includes work not because the spec was explicit that they 
should work, but because there were schemas out in the wild that other 
processors accepted and it made sense to accept them too.

I think we thrashed this out when dealing with circular xs:override in 
1.1. If you have two documents A and B which include each other, the 
spec says that the schema corresponding to A must contain the components 
corresponding to its own declarations, as well as all components from 
the schema corresponding to B, and vice versa. If you take all the 
components from all the documents reachable transitively via some 
sequence of xs:include links, then you have satisfied all the rules in 
the spec. The spec doesn't mandate this interpretation, but it certainly 
allows it, and since it doesn't define any error condition for a 
circular xs:include, and since failure to terminate isn't really an 
option, using the transitive closure seems the most reasonable reading. 
To get to this interpretation, you have to avoid reading the spec as a 
set of computations to be performed, or even of functional dependencies, 
and read it instead as a set of constraints to be satisified. The 
constraint is that schema(A) contains components(A) and schema(B), while 
schema(B) contains components(B) and schema(A), and the constraint is 
satisfied if schema(A) and schema(B) are both equal to the union of 
components(A) and components(B).

Michael Kay
Saxonica

Received on Friday, 15 April 2011 16:33:20 UTC