xmlxsdconstraintsxsd-1.0

descendant constraint conditional on top-level ancestor in XML Schema 1.0


I would like to have a descendant element conditional on the top-level ancestor type. Is it possible to model that relationship in xml schema 1.0? If so, how?

Below is my desired structure/validation behavior:

<a1>
  <b>
    <c>
      <d/> -- allowed if ancestor is a1
    </c>
  </b>
</a1>

<a2>
  <b>
    <c>
      <d/> -- validation error - not allowed if ancestor is not a1
    </c>
  </b>
</a2>

It seems that XSD 1.1 assertions would enable me to do just that, but I'm stuck with XML Schema 1.0.

I could obviously make parallel hierarchies and have the d element only allowed in one but that gets verbose and confusing for users of our schema.

The parallel hierarchy could look like this:

<a1>
  <b1>
    <c1>
      <d/> -- allowed in c1 element
    </c1>
  </b1>
</a1>

<a2>
  <b2>
    <c2>
      <d/> -- not allowed in c2
    </c2>
  </b2>
</a2>

Edit: Solution schema to above question using CM's tip

<xs:element name="a1">
    <xs:complexType>
        <xs:sequence>
            <xs:element name="b" type="b1"></xs:element>
        </xs:sequence>
    </xs:complexType>
</xs:element>
<xs:element name="a2">
    <xs:complexType>
        <xs:sequence>
            <xs:element name="b" type="b2"></xs:element>
        </xs:sequence>
    </xs:complexType>
</xs:element>
<xs:complexType name="b1">
    <xs:sequence>
        <xs:element name="c" type="c1"></xs:element>
    </xs:sequence>
</xs:complexType>
<xs:complexType name="b2">
    <xs:sequence>
        <xs:element name="c" type="c2"></xs:element>
    </xs:sequence>
</xs:complexType>
<xs:complexType name="c1">
    <xs:sequence>
        <xs:element name="d"></xs:element>
    </xs:sequence>
</xs:complexType>
<xs:complexType name="c2">
    <xs:sequence>
    </xs:sequence>
</xs:complexType>

Solution

  • Yes, it's possible. Your fallback proposal of parallel element hierarchies (b1 and c1 if you're inside a1, b2 and c2 if you're in a2) is already halfway there. What you want is essentially that same parallel hierarchy, but with the further twist that the elements you have called b1 and b2 are both called b (and similarly for c1, c2, c).

    The key is to bind the name 'b' to an element of one type (call it B1) in the context of a1, and to bind it to a different type (B2) in the context of a2. The name 'c' is then bound to one type (C1) in the context of type B1, and to a different type (C2) in the context of type B2. In type C1, d elements are allowed, and not in type C2.

    A fuller description of the technique can be found in a paper I wrote while XSD 1.0 was being developed. It may be observed that the same techniques can be applied in any schema language where the name/type binding can be local to a given context; Relax NG, for example, can do the same kind of thing.