1

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 types declared as global level elements, 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.

Community
  • 1
  • 1
GSerg
  • 76,472
  • 17
  • 159
  • 346

1 Answers1

0

Use a top-level group.

It's like your last bullet-point, but you can reference it with <xs:group ref=..."/> each time it is needed instead of duplicating the choice (or maybe you meant that).

<xs:complexType name="parentType">
  <xs:group ref="AChild" minOccurs="1" maxOccurs="unbounded" />
</xs:complexType>

<xs:group name="AChild">
  <xs:choice>
    <xs:element name="AConcreteChild" type="AConcreteChild_type" />
    <xs:element name="AnotherPossibleConcreteChild" type="AnotherPossibleConcreteChild_type" />
  </xs:choice>
</xs:group>

BTW: I also find this clearer, because the choices are grouped together in the xsd, so you don't have to scan for element declaration with the same substitution group.

13ren
  • 11,887
  • 9
  • 47
  • 64
  • One of my reasons to move away from the list was the fact each child is in its own xsd file. There is also one main xsd file, and in that file I have to 1) list all the child files in `` and then 2) list all the child types in a ``. Two lists to maintain and keep in synch. I wanted slice it down to just one list (of ``s). – GSerg Dec 28 '12 at 09:12