none
Sequence vs Choice vs All

    Question

  • Hi,

     

    We have an XML Schema to validate the XML data that our clients can submit to our system, which has several sections similar to "Schema 1" in the code snippet at the bottom of the page...

     

    This was working fine, until we had a new requirement, to allow the users to submit the elements in any order. With a sequence, it was expecting either OptionalElement1 or RequiredElement1 to be the first element listed. So with that in mind, we proceeded to change the Sequence indicator to a Choice.

     

    This is the way it is now, and it is working, except for one slight issue. The individual minOccurs constraints are not being followed. For example, RequiredElement1 is no longer required, so if the element is left out of the XML, it will validate successfully against the schema, but cause errors later on, when the RequiredElement1 element is expected.

     

    So I did some research and found the All indicator. This is ALMOST what we want, except again for one problem. The OptionalUnboundedElement is invalid, because each element is optional (if minOccurs is 0) but can ONLY be listed once.

     

    The schema can be changed, but not the elements in the schema, because the client would have to adapt their systems to the new schema, so we need to wait for the next release cycle. If this wasn't the case, we could do what is displayed in "Schema 2".

     

    Are there any other possibilities that I'm missing?

     

    Thanks,
    Evan

     

    Code Snippet


    Schema 1:

    ---------

    <xs:element name="ParentElement">

    <xs:complexType>

    <xs:sequence>

    <xs:element ref="OptionalElement1" minOccurs="0"/>

    <xs:element ref="RequiredElement1"/>

    <xs:element ref="RequiredElement2"/>

    <xs:element ref="OptionalUnboundedElement" minOccurs="0" maxOccurs="unbounded"/>

    <xs:element ref="OptionalElement2" minOccurs="0"/>

    </xs:sequence>

    </xs:complexType>

    </xs:element>

     

    Schema 2:

    ---------

    <xs:element name="ParentElement">

    <xs:complexType>

    <xs:all minOccurs="0" maxOccurs="1">

    <xs:element ref="OptionalElement1" minOccurs="0"/>

    <xs:element ref="RequiredElement1"/>

    <xs:element ref="RequiredElement2"/>

    <xs:element ref="OptionalUnboundedGroup" minOccurs="0"/>

    <xs:element ref="OptionalElement2" minOccurs="0"/>

    </xs:all>

    </xs:complexType>

    </xs:element>

    <xs:element "OptionalUnboundedGroup">

    <xs:complexType>

    <xs:sequence>

    <xs:element ref="OptionalUnboundedElement" minOccurs="1" maxOccurs="unbounded"/>

    </xs:sequence>

    </xs:complexType>

    </xs:element>

     

     

    Wednesday, May 14, 2008 6:48 PM

Answers

  • Hi Evan,

     

    <xs:key> constraint does two things: it checks for uniqueness and it also requires the node to be present in the XML document.  Here's an example:

     

    <xs:element name="ParentElement">

      <xs:complexType>

        <xs:choice minOccurs="2" maxOccurs="unbounded">

          <xs:element ref="OptionalElement1" minOccurs="0"/>

          <xs:element ref="RequiredElement1"/>

          <xs:element ref="RequiredElement2"/>

          <xs:element ref="OptionalUnboundedElement" minOccurs="0" maxOccurs="unbounded"/>

          <xs:element ref="OptionalElement2" minOccurs="0"/>

        </xs:choice>

      </xs:complexType>

      <xs:key name="requiredElement1">

        <xsTongue Tiedelector xpath="."/>

        <xs:field xpath="tns:RequiredElement1"/>

      </xs:key>

      <xs:key name="requiredElement2">

        <xsTongue Tiedelector xpath="."/>

        <xs:field xpath="tns:RequiredElement2"/>

      </xs:key>

    </xs:element>

    Stan

    Friday, May 16, 2008 9:31 PM

All replies

  • Hi Evan,

     

    If I understand your requirements, what you need is a choice with minOccurs=<number-of-required-elements> and maxOccurs="unbounded" as well as xs:key constraints to check for required elements. 

     

    Let me know if you need an example,

    Stan

    Thursday, May 15, 2008 4:01 PM
  •  

    Hi Stan,

     

    Thanks for your reply.

     

    The issue that I saw with Choice was that you could choose not to submit a required element, so an element like RequiredElement1 could be skipped even though its maxOccurs was not 0. I thought of making the Choice's minOccurs = "2", i.e. requiring RequiredElement1 and RequiredElement2 like you said. However, the problem that I see with this, is that if someone provided OptionalElement1 and OptionalElement2, then that would satisfy the minOccurs = 2 constraint.

     

    So does the xs:key thing fix this last issue? I'm not familiar with xs:key, so I looked into it and found this... http://www.w3schools.com/Schema/el_key.asp and I can't really understand from that what it is supposed to do. If it's not too much trouble to provide an example, I'd really appreciate it. So far I have...

     

    Code Snippet

    <xs:element name="ParentElement">

    <xs:complexType>

    <xs:choice minOccurs="2" maxOccurs="unbounded">

    <xs:element ref="OptionalElement1" minOccurs="0"/>

    <xs:element ref="RequiredElement1"/>

    <xs:element ref="RequiredElement2"/>

    <xs:element ref="OptionalUnboundedElement" minOccurs="0" maxOccurs="unbounded"/>

    <xs:element ref="OptionalElement2" minOccurs="0"/>

    </xs:choice>

    </xs:complexType>

    </xs:element>

     

     

    Thanks a lot,

    Evan

    Friday, May 16, 2008 3:23 PM
  • Hi Evan,

     

    <xs:key> constraint does two things: it checks for uniqueness and it also requires the node to be present in the XML document.  Here's an example:

     

    <xs:element name="ParentElement">

      <xs:complexType>

        <xs:choice minOccurs="2" maxOccurs="unbounded">

          <xs:element ref="OptionalElement1" minOccurs="0"/>

          <xs:element ref="RequiredElement1"/>

          <xs:element ref="RequiredElement2"/>

          <xs:element ref="OptionalUnboundedElement" minOccurs="0" maxOccurs="unbounded"/>

          <xs:element ref="OptionalElement2" minOccurs="0"/>

        </xs:choice>

      </xs:complexType>

      <xs:key name="requiredElement1">

        <xsTongue Tiedelector xpath="."/>

        <xs:field xpath="tns:RequiredElement1"/>

      </xs:key>

      <xs:key name="requiredElement2">

        <xsTongue Tiedelector xpath="."/>

        <xs:field xpath="tns:RequiredElement2"/>

      </xs:key>

    </xs:element>

    Stan

    Friday, May 16, 2008 9:31 PM
  • Thanks for your help! I will try that out.

    Monday, May 19, 2008 1:52 PM
  • That worked great for the most part. However, some of the elements that are referenced are complex types and it says for those that it expects a simple type. So for example if RequiredElement1 references a simple type, the key works for that, but then if RequiredElement2 references a complex type, it gives the error:

     

    The field 'RequiredElement2' is expecting an element or attribute with simple type or simple content.

     

    This is not such a big deal because there are only 3 instances of required complex types, so we can catch those in our code.

    Monday, May 19, 2008 2:45 PM
  • Yes, xs:key needs simple type nodes.  What you can do is adjust the key to look for a required simple-type element child of your complex types.

     

    Stan

     

    Tuesday, May 20, 2008 6:59 PM