Search code examples
xmlxsdxsd-validationxml-validationrelaxng

Why can't I put an xs:all inside a xs:sequence?


I'm still a bit new to XML Schema, and I'm trying to do something that would look like this in Relax NG Compact:

test = element test{
element A {text},
element B {text},
(element C {text}? &
element D {text}?)
}

Which means that in the test element contains A, then B, then in any order C and D, which are both optional.

The way I see it, I should be able to simply put

<xs:element name="test">
    <xs:complexType>
        <xs:sequence>
            <xs:element name="A"/>
            <xs:element name="B"/>
            <xs:all>
                <xs:element name="C"/>
                <xs:element name="D"/>
            </xs:all> 
        </xs:sequence>
    </xs:complexType>
</xs:element>

But it won't let me put an <xs:all> inside an <xs:sequence>. Saying

s4s-elt-must-match.1: The content of 'sequence' must match (annotation?, (element | group | choice | sequence | any)*). A problem was found starting at: all.

So I tried taking <xs:all> out of <xs:sequence> like so:

<xs:element name="test">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="A" />
                <xs:element name="B"/>
            </xs:sequence>
            <xs:all>
                <xs:element name="C"/>
                <xs:element name="D"/>
            </xs:all> 
        </xs:complexType>
    </xs:element>

But now it still doesn't work, saying

s4s-elt-invalid-content.1: The content of '#AnonType_test' is invalid. Element 'all' is invalid, misplaced, or occurs too often

So I'm confused because it seems so simple, yet I'm not figuring out how to do this.


Solution

  • Your confusion is understandable. The problem is that XSD design is irregular, and irregular designs often violate our expectations.

    Here's a work-around, which is unfortunately more verbose and also impractical for larger numbers of elements to be permuted:

      <xs:element name="test">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="A"/>
            <xs:element name="B"/>
            <xs:choice minOccurs="0">
              <xs:sequence>
                <xs:element name="C"/>
                <xs:element name="D" minOccurs="0"/>
              </xs:sequence>
              <xs:sequence>
                <xs:element name="D"/>
                <xs:element name="C" minOccurs="0"/>
              </xs:sequence>
            </xs:choice>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    

    Another workaround is to impose an ordering; allowing any order often isn't important in practice.