In an XSD schema, you cannot declare an element as the only valid root node for your document.
It's a PITA, but I'm aware about it.
For ages I would simply do what is suggested in the linked answer -- only define <simpleType>
s and <complexType>
s, with the only <element>
defined at the global level being my desired root node.
However, I'm currently up to a nice refactoring of my XSD/XSLT code base. One of the things I want to do is to restrict a certain element to only elements derived from a desired type, provided these derivatives can have different node names:
<xs:complexType name="parentType">
<xs:sequence>
<xs:element ref="AChild" minOccurs="1" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
where AChild
is an abstract base type from which other types will derive using substitutionGroup
:
<xs:complexType name="child_base" abstract="true">
...
</xs:complexType>
<xs:element name="AChild" type="child_base" abstract="true" />
<xs:element name="AConcreteChild" substitutionGroup="AChild" >
<xs:complexType>
<xs:complexContent>
<xs:extension base="child_base">
...
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
<xs:element name="AnotherPossibleConcreteChild" substitutionGroup="AChild" >
<xs:complexType>
<xs:complexContent>
<xs:extension base="child_base">
...
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
The problem here is that the substitutionGroup
thing only works for elements declared at the global level. So now I have a bunch of previously internal type
s declared as global level element
s, and while that perfectly restricts the possible children for parentType
, it also means the validation will succeed if any of the now-global children is provided as a root element, which I don't want.
Options I have considered included:
- Ditch the
substitutionGroup
inheritance, move all the possible children to a separate namespace, and use<xsd:any namespace="that namespace" />
. Feels sort of okay, but I don't like the additional namespace and the worse-defined constraint. - Ignore the problem at the XSD level and check the root node name and namespace in the code that uses the XSD template. What I did not like here was breaking the separation of concerns, as in my design the XSD file was a black box for the calling code, and I would rather not introduce a hardcoded dependency on a node QName.
Introduce a principle according to which there are always going to be two "main" XSD schemas. One will validate the nodes in the usual way (the validation I currently have), another one will only contain a definition of the top-level node in the most laxed form:
<xs:complexType name="parentType"> <xs:sequence> <xs:any namespace="##any" processContents="skip" /> </xs:sequence> <xs:anyAttribute namespace="##any" processContents="skip" /> </xs:complexType> <xs:element name="TheRootNode" type="parentType" />
And then my document will be correct if and only if both schemas validate.
What I don't like here is that I'm not sure how deeply that violates best practices.Quit refactoring and keep what I had before (and before I had all possible children manually listed in an
<xs:choice>
).
My question is, is there any other way to make the any-derived-element constraint work without declaring multiple global-level <element>
s (so that the only-root-node constraint works again)? Also please leave an answer if you believe I better choose one of the listed options.