2

I am trying to design a XSD for 2 different XML message coming in:

<message>
    <common1>value1</common1>
    <common2>value2</common2>
    <common3>
        <unique1>hello</unique1>
    </common3>
    <common4>
        <unique2>bye</unique2>
    </common4>
</message>

or

<message>
    <common1>value1</common1>
    <common2>value2</common2>
    <common3>
        <unique3>hey</unique3>
    </common3>
    <common4>
        <unique4>goodbye</unique4>
    </common4>
</message>

Since i see that they have common elements and only unique nested elements, i want to create a generic parent that an xsd can extend so i can just worry about the unique fields but i still don't have an idea on how to define common3 or 4 in parent level so i have defined it on the child xsds which i think is wrong, can anyone verify and also shed any light on this?

parent.xsd:
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="message">
      <xs:complexType>
        <xs:sequence>
          <xs:element name="common1" type="xs:string"/>
          <xs:element name="common2" type="xs:string"/>
        </xs:sequence>
      </xs:complexType>
    </xs:element>
</xs:schema>

and

child1.xsd:
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:include schemaLocation="parent.xsd"/>
    <xs:complexType>
        <xs:complexContent>
            <xs:extension base="message">
                <xs:sequence>
                    <xs:element name="common3" type="common3Type" />
                    <xs:element name="common4" type="common4Type" />
                </xs:sequence>
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>
    <xs:complexType name="common3Type">
      <xs:sequence>
          <xs:element name="unique1" type="xs:string"/>
      </xs:sequence>
    </xs:complexType>
    <xs:complexType name="common4Type">
      <xs:sequence>
          <xs:element name="unique2" type="xs:string"/>
      </xs:sequence>
    </xs:complexType>
</xs:schema>

and

child2.xsd:
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:include schemaLocation="parent.xsd"/>
    <xs:complexType>
        <xs:complexContent>
            <xs:extension base="message">
                <xs:sequence>
                    <xs:element name="common3" type="common3Type" />
                    <xs:element name="common4" type="common4Type" />
                </xs:sequence>
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>
    <xs:complexType name="common3Type">
      <xs:sequence>
          <xs:element name="unique3" type="xs:string"/>
      </xs:sequence>
    </xs:complexType>
    <xs:complexType name="common4Type">
      <xs:sequence>
          <xs:element name="unique4" type="xs:string"/>
      </xs:sequence>
    </xs:complexType>
</xs:schema>
R.C
  • 573
  • 3
  • 7
  • 19
  • Use choice instead of extending, it will be simpler. https://www.w3schools.com/xml/el_choice.asp – sashwat May 24 '18 at 04:18

1 Answers1

2

You can use extension-by-restriction with XML Schema such that you have a generic definition for common3 and common4 in the super-type, and then constrain those definitions for your child1 and child2 message sub-types, respectively:

<!-- message.xsd -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:complexType name="message">
    <xs:sequence>
      <xs:element name="common1" type="xs:string"/>
      <xs:element name="common2" type="xs:string"/>
      <xs:element name="common3" type="xs:anyType" minOccurs="0"/>
      <xs:element name="common4" type="xs:anyType" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="message-subtype-a">
    <xs:complexContent>
      <xs:restriction base="message">
        <xs:sequence>
          <xs:element name="common1" type="xs:string"/>
          <xs:element name="common2" type="xs:string"/>
          <xs:element name="common3" type="common3-subtype-a" minOccurs="1"/>
          <xs:element name="common4" type="common4-subtype-a" minOccurs="1"/>
        </xs:sequence>
      </xs:restriction>
    </xs:complexContent>
  </xs:complexType>

  <xs:complexType name="message-subtype-b">
    <xs:complexContent>
      <xs:restriction base="message">
        <xs:sequence>
          <xs:element name="common1" type="xs:string"/>
          <xs:element name="common2" type="xs:string"/>
          <xs:element name="common3" type="common3-subtype-b" minOccurs="1"/>
          <xs:element name="common4" type="common4-subtype-b" minOccurs="1"/>
        </xs:sequence>
      </xs:restriction>
    </xs:complexContent>
  </xs:complexType>

  <xs:complexType name="common3-subtype-a">
    <xs:sequence>
      <xs:element name="unique1" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="common4-subtype-a">
    <xs:sequence>
      <xs:element name="unique2" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="common3-subtype-b">
    <xs:sequence>
      <xs:element name="unique3" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="common4-subtype-b">
    <xs:sequence>
      <xs:element name="unique4" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>

</xs:schema>

Note I've put all type definitions in a single schema file here. For declaring elements you still need two schemas for the respective message sub-types, since you want the messages to be both contained in a message element:

<!-- message-a.xsd -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:include schemaLocation="message.xsd"/>
  <xs:element name="message" type="message-subtype-a"/>
</xs:schema>

and

<!-- message-b.xsd -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:include schemaLocation="message.xsd"/>
  <xs:element name="message" type="message-subtype-b"/>
</xs:schema>

When using derivation-by-restriction, you must repeat the content model for each individual sub-type, as explained in XML Schema Restriction for Complex types : Complete Redefinition? by one of the authors of the XML Schema specification.

imhotap
  • 2,275
  • 1
  • 8
  • 16
  • hello, thanks for your reply, will this also be feasible for scenarios that we have unlimited unknown version of the common3/4 instead of 2 version? if not, what else would you suggest? the ideal solution would hopefully allow any xsd to extend everything and just have their own unique sub elements under common3 and common4, thanks! – R.C May 24 '18 at 13:05
  • I'd suggest to check out XML Schema *wildcards* which are basically particles in your content model that validate *any* element when occuring in that position (or any declared element, or any element in a particular namespace, etc.); see eg. https://stackoverflow.com/questions/943659/how-can-i-define-an-xsd-file-that-allows-unknown-wildcard-elements – imhotap May 24 '18 at 14:24