Search code examples
xmlxsdxsd-validationxml-validation

Group ref depending on element value


I'd like to validate xml file so that according to element's value a particular group of elements is required.

For example I have few types of label printers: CAB, Intermec etc. which configuration should be set using xml file. Printers may have few common settings but should also have type-specific settings.

This is my current simplified xml schema (for now only for 2 types):

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="printer">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="type">
          <xs:simpleType>
            <xs:restriction base="xs:string">
              <xs:enumeration value="CAB"/>
              <xs:enumeration value="Intermec"/>
            </xs:restriction>
          </xs:simpleType>
         </xs:element>
        <xs:element name="connected" type="xs:string"/>
        <xs:element name="id" type="xs:string"/>
        <xs:group ref="CabSettings" minOccurs="0"/>
        <xs:group ref="IntermecSettings" minOccurs="0"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:group name="CabSettings">
    <xs:sequence>
      <xs:element name="portname" type="xs:string"/>
      <xs:element name="baudrate" type="xs:int"/>
      <xs:element name="parity" type="xs:string"/>
    </xs:sequence>
  </xs:group>
  <xs:group name="IntermecSettings">
    <xs:sequence>
      <xs:element name="ipaddress" type="xs:string"/>
      <xs:element name="port" type="xs:integer"/>
    </xs:sequence>
  </xs:group>
</xs:schema>

This is where I've stopped.. How may I demand to expect type specific group to be present in xml according to type element value? Is it even possible to do such thing? May it be done using XSD 1.0?

XML examples:

<printer>
    <type>CAB</type>
    <connected>true</connected>
    <id>CAB1</id>
    <portname>COM2</portname>
    <baudrate>57600</baudrate>
    <parity>NONE</parity>
</printer>

<printer>
    <type>Intermec</type>
    <connected>true</connected>
    <id>Intermec1</id>
    <ipaddress>127.0.0.1</ipaddress>
    <port>1</port>
</printer>

Solution

  • XSD 1.0

    You have to differentiate type based upon element name. So, rather than a single printer element, you'd have separate CABPrinter and IntermecPrinter elements. You could continue to use groups of elements to consolidate common definitional components as you do now.

    XSD 1.1

    You could use Conditional Type Assignment to differentiate the type of printer based upon the value of an attribute, or you could use assertions to constrain the content model based upon the value of an element.