Search code examples
xmlxsdschema-design

XML Schema: Permit a tag only if another optional tag is provided


I'm trying to define an XML schema that has an optional tag, sort_expression. If that optional tag is provided, then a second optional tag, alternate_sort_expression is allowed, but it is conditional on the existence of the first tag.

For example, I want these examples to validate:

<indication>
    <label>A label for the item</label>
    <sort_expression>Some Value</sort_expression>
    <!-- one sort expression was provided -->
</indication>

or

<indication>
    <label>A label for the item</label>
    <!-- no sort expression was provided -->
</indication>

or

<indication>
    <label>A label for the item</label>
    <sort_expression>Some Value</sort_expression>
    <alternate_sort_expression>Some Value</alternate_sort_expression>
</indication>

but the following should not pass validation:

<indication>
    <label>A label for the item</label>
    <!-- no main sort expression was provided -->
    <alternate_sort_expression>INVALID</alternate_sort_expression>
</indication>

I thought the following schema, using a choice of two sequences would work. Unfortunately the schema itself is not validating; Altova XML Spy is telling me "the content model of complex type indication is ambiguous:

<xs:complexType name="indication">
<xs:sequence>
  <xs:element name="label" type="xs:string"/>
  <xs:choice>
    <xs:sequence>
      <xs:element name="sort_expression" type="xs:string" minOccurs="0"/>
    </xs:sequence>
    <xs:sequence>
      <xs:element name="sort_expression" type="xs:string"/>
      <xs:element name="alternate_sort_expression" type="xs:string" maxOccurs="unbounded"/>
    </xs:sequence>
  </xs:choice>
</xs:sequence>


Solution

  • Create an optional sequence that contains a mandatory <sort_expression> element and optional <alternate_sort_expression> elements.

    Because they are in the same sequence, <alternate_sort_expression> appears only when <sort_expression> is present but also <sort_expression> can be omitted because the whole sequence can be omitted.

    <xs:complexType name="indication">
      <xs:sequence>
        <xs:element name="label" type="xs:string"/>
        <xs:sequence minOccurs="0">
          <xs:element name="sort_expression" type="xs:string"/>
          <xs:element name="alternate_sort_expression" minOccurs="0" maxOccurs="unbounded" type="xs:string"/>
        </xs:sequence>
      </xs:sequence>
    </xs:complexType>