How do you make an XSD element required or not required depending on the context?

tjg184 picture tjg184 · Oct 23, 2012 · Viewed 19k times · Source

We have a definition of Person element where we want different elements to be required depending on what they are doing. For example, if they are adding a Person, then different elements are required to be sent versus updating a Person. Below in the example, the Person type is currently duplicated, which of course is wrong. Is there a good way of representing this in the xsd so we can reuse the Person type.

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:complexType name="Person">
        <xs:annotation>
            <xs:documentation>This is the definition when changing a person</xs:documentation>
        </xs:annotation>
        <xs:sequence>
            <xs:element name="PartyName" type="xs:string" minOccurs="0" maxOccurs="1"/>
            <xs:element name="GenderCode" type="GenderCode_Type" minOccurs="0" maxOccurs="1"/>
            <xs:element name="BirthDate" type="xs:date" minOccurs="0" maxOccurs="1"/>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="Person">
        <xs:annotation>
            <xs:documentation>This is the definition when adding a person</xs:documentation>
        </xs:annotation>
        <xs:sequence>
            <xs:element name="PartyName" type="xs:string" minOccurs="1" maxOccurs="1"/>
            <xs:element name="GenderCode" type="GenderCode_Type" minOccurs="1" maxOccurs="1"/>
            <xs:element name="BirthDate" type="xs:date" minOccurs="0" maxOccurs="1"/>
        </xs:sequence>
    </xs:complexType>   
</xs:schema>

Answer

C. M. Sperberg-McQueen picture C. M. Sperberg-McQueen · Oct 25, 2012

The simplest way to have two different types for Person elements is to use local declarations of Person in the two different contexts you have in mind. For example, you might say:

<xs:element name="Add">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="Person" type="AddPerson"/>
    </xs:sequence>
  </xs:complexType>
</xs:element>

<xs:element name="Update">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="Person" type="ChangePerson"/>
    </xs:sequence>
  </xs:complexType>
</xs:element>

This example assumes that you have redefined your two complex types as AddPerson and ChangePerson.

If additionally you want to have the two complex types be explicitly related, you can derive them both by restriction from a generic Person type.

<xs:complexType name="Person">
  <xs:annotation>
    <xs:documentation>This is the generic 
      definition for persons</xs:documentation>
  </xs:annotation>
  <xs:sequence>
    <xs:element name="PartyName" type="xs:string" 
                minOccurs="0" maxOccurs="1"/>
    <xs:element name="GenderCode" type="GenderCode_Type" 
                minOccurs="0" maxOccurs="1"/>
    <xs:element name="BirthDate" type="xs:date" 
                minOccurs="0" maxOccurs="1"/>
  </xs:sequence>
</xs:complexType>

<xs:complexType name="ChangePerson">
  <xs:annotation>
    <xs:documentation>This is the definition 
      when changing a person</xs:documentation>
  </xs:annotation>
  <xs:complexContent>
    <xs:restriction base="Person">
      <xs:sequence>
        <xs:element name="PartyName" type="xs:string" 
                    minOccurs="0" maxOccurs="1"/>
        <xs:element name="GenderCode" type="GenderCode_Type" 
                    minOccurs="0" maxOccurs="1"/>
        <xs:element name="BirthDate" type="xs:date" 
                    minOccurs="0" maxOccurs="1"/>
      </xs:sequence>        
    </xs:restriction>
  </xs:complexContent>
</xs:complexType>

<xs:complexType name="AddPerson">
  <xs:annotation>
    <xs:documentation>This is the definition 
      when adding a person</xs:documentation>
  </xs:annotation>
  <xs:complexContent>
    <xs:restriction base="Person">
      <xs:sequence>
        <xs:element name="PartyName" type="xs:string" 
                    minOccurs="1" maxOccurs="1"/>
        <xs:element name="GenderCode" type="GenderCode_Type" 
                    minOccurs="1" maxOccurs="1"/>
        <xs:element name="BirthDate" type="xs:date" 
                    minOccurs="0" maxOccurs="1"/>
      </xs:sequence>        
    </xs:restriction>
  </xs:complexContent>
</xs:complexType>  

Here, the generic type Person is identical to the AddPerson type; I've defined AddPerson using a vacuous restriction just for the symmetry of deriving both of the operation-specific types from the generic type.

Whether having such an explicit relation among your types actually helps you achieve your goals will depend, of course, in part on what use your system makes of your schema type definitions.