views:

45

answers:

3

Please enlighten me why XML Spy thinks this is valid. FYI, this specifies an SQL query. Here the XML:

 <sideBar title="LabelSearch">
  <searchLabel table="ID=*.companies">
   <filter accessRight="r">
    <and>
     <filterElement argument="companies.Type" operator="=" value="Client"/>
    </and>
   </filter>
  </searchLabel>
 </sideBar>

The problem: I should not be allowed to put in only one filterElement inside the "and" tag, but at least two. If I only have one filterElement, I should use it without the surrounding "and" tag. Here the XSD:

 <xs:complexType name="filterGroupType">
  <xs:sequence>
   <xs:choice>
    <xs:element name="or" type="filterGroupOrType"/>
    <xs:element name="and" type="filterGroupAndType"/>
    <xs:element name="filterElement" type="filterType"/>
   </xs:choice>
  </xs:sequence>
  <xs:attribute name="accessRight" type="accessRightSimpleType" use="required"/>
 </xs:complexType>
 <xs:complexType name="filterGroupAndType">
  <xs:sequence minOccurs="2" maxOccurs="unbounded">
   <xs:element name="or" type="filterGroupOrType" minOccurs="0"/>
   <xs:element name="filterElement" type="filterType" minOccurs="0"/>
  </xs:sequence>
 </xs:complexType>
 <xs:complexType name="filterGroupOrType">
  <xs:sequence minOccurs="2" maxOccurs="unbounded">
   <xs:element name="and" type="filterGroupAndType" minOccurs="0"/>
   <xs:element name="filterElement" type="filterType" minOccurs="0"/>
  </xs:sequence>
 </xs:complexType>
 <xs:complexType name="filterType">
  <xs:attribute name="argument" type="xs:string" use="required"/>
  <xs:attribute name="operator" type="operatorSimpleType" use="required"/>
  <xs:attribute name="value" type="xs:anySimpleType"/>
  <xs:attribute name="field" type="fieldTitleSimpleType"/>
 </xs:complexType>

Thanks in advance.

+1  A: 

You have a minOccurs="0" on filterElement. So a single filterElement can be seen as a filterElement 0 times, followed by a filterElement. A valid sequence. Maybe you should avoid mixing minOccurs in xs:sequence and xs:element in your schema...

Damien
I changed the structure to xs:choice and it worked. I don't get your explanation, though. I'll do some reading on these constructors. Thanks!
PeerBr
+3  A: 

Briefly

  1. Document is valid because elements have minOccurs="0".
  2. Use <xs:choice> instead of <xs:sequence>.

A bit longer answer.

Just like @Damien said, that XML is valid because this part of your schema allows "empty" sequences.

<xs:sequence minOccurs="2" maxOccurs="unbounded">
  <xs:element name="or" type="filterGroupOrType" minOccurs="0"/>
  <xs:element name="filterElement" type="filterType" minOccurs="0"/>
</xs:sequence>

With <xs:sequence minOccurs="2" maxOccurs="unbounded"> You define that "this sequence must appear at least twice". At the same time <xs:element name="or" type="filterGroupOrType" minOccurs="0"/> Allows these elements within the sequence to be absent. Metaphorically it is like saying "You must order a meal twice but you don't have to eat any of the meals you ordered."

Instead if you want to always have at least 2 child elements and these children can be<filterElement> or <or> elements in any order, you should use <xs:choice> with minOccurs="1"

<xs:choice minOccurs="2" maxOccurs="unbounded">
  <xs:element name="or" type="filterGroupOrType" minOccurs="1"/>
  <xs:element name="filterElement" type="filterType" minOccurs="1"/>
</xs:choice>

The default value for minOccurs is 1 so you can leave it out and keep your code cleaner and shorter. <xs:choice> selects one of its children and repeats choosing at least minOccurs times. If at least one of choices can has minOccurs="0" then the choice will also allow "empty" selections.

jasso
@jasso: Thank you for the very good explanation. As stated above, I followed that without changing the minOccurs either for xs:choice nor xs:element. That had the effect I wanted: Any two items or more, in any order.
PeerBr
So does `filterElement` and `or` still have `minOccurs="0"` in your schema? If so, then your original document would still be valid (which you didn't want to happen) even if you used `<xs:choice minOccurs="2">` because `minOccurs="0"` on the element definitions allows the validator to select an element 0 times.
jasso
A: 

You have a sequence that must occur twice, but elements in the sequence are optional (minOccurs="0"). The sequence itself doesn't represent any XML, it just defines the possible elements it can contain and the order they must be in. A perfectly valid sequence can be empty in that case.

Replacing <xs:sequence> with <xs:choice> and changing minOccurs to 1 on the subelements will work if you do not care what order the elements appear in and it looks like you don't. If you don't set minOccurs to 1 on the children then a valid choice would still be the element occurring 0 times and your XML would validate. If you set minOccurs to 2 on the child elements then you would have a minimum of 4 elements since you would make a choice twice and pick from each child element occurring twice each time.

Jason Goemaat
@Jason: Thanks for your answer as well! I really get the subtleties of xs:choice now, that helped a lot.
PeerBr