XSD - how to allow elements in any order any number of times?

Viewed 120574

I am trying to create an XSD, and trying to write the definition with the following requirement:

  • Allow child element specified to appear any number of times (0 to unbounded)
  • Allow child elements to be in any order

I looked around and found various solutions like this:

<xs:element name="foo">
  <xsl:complexType>
    <xs:choice minOccurs="0" maxOccurs="unbounded">
      <xs:element name="child1" type="xs:int"/>
      <xs:element name="child2" type="xs:string"/>
    </xs:choice>
  </xs:complexType>
</xs:element>

But from what I understand xs:choice still only allows single element selection. Hence setting the MaxOccurs to unbounded like this should only mean that "any one" of the child elements can appear multiple times. Is this accurate?

If above solution is incorrect, how can I achieve what I stated above in my requirement?

EDIT: What if the requirement is as follows?

  • Element child1 child2 can appear any number of times (0 to unbounded)
  • Elements to be in any order
  • Elements child3 and child4 should appear exactly once.

For example, this xml is valid:

<foo>
<child1> value </child1>
<child1> value </child1>
<child3> value </child3>
<child2> value </child2>
<child4> value </child4>
<child1> value </child1>
</foo>

but this is not (missing child3)

<foo>
<child1> value </child1>
<child1> value </child1>
<child2> value </child2>
<child4> value </child4>
<child1> value </child1>
</foo>
7 Answers

In the schema you have in your question, child1 or child2 can appear in any order, any number of times. So this sounds like what you are looking for.

If you wanted only one of them to appear an unlimited number of times, the unbounded would have to go on the elements instead:

<xs:element name="foo">
   <xs:complexType>
     <xs:choice maxOccurs="unbounded">
       <xs:element name="child1" type="xs:int" maxOccurs="unbounded"/>
       <xs:element name="child2" type="xs:string" maxOccurs="unbounded"/>
     </xs:choice>
   </xs:complexType>
</xs:element>

But from what I understand xs:choice still only allows single element selection. Hence setting the MaxOccurs to unbounded like this should only mean that "any one" of the child elements can appear multiple times. Is this accurate?

No. The choice happens individually for every "repetition" of xs:choice that occurs due to maxOccurs="unbounded". Therefore, the code that you have posted is correct, and will actually do what you want as written.

You should find that the following schema allows the what you have proposed.

  <xs:element name="foo">
    <xs:complexType>
      <xs:sequence minOccurs="0" maxOccurs="unbounded">
        <xs:choice>
          <xs:element maxOccurs="unbounded" name="child1" type="xs:unsignedByte" />
          <xs:element maxOccurs="unbounded" name="child2" type="xs:string" />
        </xs:choice>
      </xs:sequence>
    </xs:complexType>
  </xs:element>

This will allow you to create a file such as:

<?xml version="1.0" encoding="utf-8" ?>
<foo>
  <child1>2</child1>
  <child1>3</child1>
  <child2>test</child2>
  <child2>another-test</child2>
</foo>

Which seems to match your question.

If you have very few child elements, then you could list all possible sequences inside a <xs:choice>. That gives per sequence the flexibility you want. As N! is growing very rapidly, this only suits up to ~4 child elements.

Related