3

This is a similar question to How to create a schema for an unordered list of XML nodes, with occurrence constraints, but actually slightly simpler. However I am having great trouble understanding the logic behind sequences and choices (and especially when they are nested into sequences of choices or choices of sequences), and although I've studied it for a long time I can't understand how the example above works.

What I need is schema for a list of nodes, ChildA and ChildB, whereby ChildA can occur 0-n times, but ChildB only 0-1 times. (Actually I need several nodes of each type, but if I can do it for ChildA and ChildB, extending it to ChildX etc. and ChildY etc. should be simple). There should be no order constraint. I'd appreciate any help. Any links that explain schema indicators in depth would also be helpful.

Community
  • 1
  • 1
Dave
  • 3,429
  • 2
  • 26
  • 29

3 Answers3

3

This would be the simplest solution that quickly came to my mind. The key point here is to use another sequence inside the "main" sequence. The schema is kept deterministic by setting the inner sequence to start with <ChildB> and <ChildB> is kept optional by setting the cardinality of that sequence to 0-1.

This is an XMLSchema 1.0 solution.

<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <!-- Schema for elements ChildA and ChildB
      The requirements are as follows:
          * ChildA and ChildB may occur in any order.
          * ChildA is optional and may occur multiple times.
          * ChildB is optional and may occur once only.
  -->

  <xs:element name="root">
    <xs:complexType>
      <xs:sequence>
        <xs:element maxOccurs="unbounded" name="AB-container" type="AB-type" />
      </xs:sequence>
    </xs:complexType>
  </xs:element>

  <xs:complexType name="AB-type">
    <xs:sequence>
      <xs:element minOccurs="0" maxOccurs="unbounded" name="ChildA" type="xs:string" />
      <xs:sequence minOccurs="0">
        <xs:element name="ChildB" type="xs:string" />
        <xs:element minOccurs="0" maxOccurs="unbounded" name="ChildA" type="xs:string" />
      </xs:sequence>
    </xs:sequence>
  </xs:complexType>

</xs:schema>
jasso
  • 13,736
  • 2
  • 36
  • 50
  • Jasso. Many apologies, I should have thanked you for this. I had to get on with higher priority tasks. I still haven't had a chance to look at it properly but I'm going to tick it as answered as it has been decided that we're not too worried about the ordering restriction after all so I may never get a chance to really get to grips with it. Sorry. – Dave Apr 24 '13 at 16:28
1

Short answer is that it cannot be done in XSD 1.0; in XSD 1.1 you could use an xsd:all compositor (since the restriction from XSD 1.0 of having only maxOccurs = 1 has been removed) - however, XSD 1.1 's problems are that i) it is only available freely as a beta Xerces version - as far as I know, and at this time; ii) there's a SAXON edition supporting it, last time I saw references to it you would have to pay for that and iii) you would have a hard time interoperating with other folks since most of them are still on XSD 1.0.

IF you can use Schematron - definitely more accessible than XSD 1.1 since it is just XSLT 1.0/2.0, then it should be easy to code it such that the count of particular element particles meets a specified criteria; it would augment an XSD where the compositor would be a repeating xsd:choice, where the choice options are elements from your allowed set.

Some people try to explain XSD compositors by making a parallel with constructs from regular expressions. If you are familiar with that, then xsd:all in XSD 1.0 is similar to square brackets (much simpler though, no concept of a range or negation), xsd:choice is like | (pipe, alternation) and xsd:sequence is the rest (where it matters the order in which you write your stuff).

I see that other people on SO recommend W3Schools. I didn't try it myself, hence me passing this on to you with the disclaimer.

Petru Gardea
  • 21,373
  • 2
  • 50
  • 62
  • That's a shame. According to my referenced thread: "By combining and nesting the various groups provided by XML Schema, and by setting the values of minOccurs and maxOccurs, it is possible to represent any content model expressible with an XML 1.0". I was hoping Jasso would pick this up as he provided a solution to the more complex problem. I'll keep trying. – Dave Jan 31 '13 at 15:45
0

@Dave is adding some dumb attribute to ChildB okay? Since your requirement on childB is 0-1 we can achieve the desired solution by adding a fixed attribute to childB and enforcing unique constraint on the attribute.

<complexType name="childAType">
 <simpleContent>
   <extension base="string"></extension>
 </simpleContent>
</complexType>


<complexType name="childBType">
 <simpleContent>
   <extension base="string">
     <attribute name="value" type="string" fixed="123"></attribute>
   </extension>
 </simpleContent>
</complexType>


<element name="root">
 <complexType>
   <choice minOccurs="0" maxOccurs="unbounded">
        <element name="childA" type="tns:childAType" minOccurs="0" maxOccurs="unbounded"></element>
        <element name="childB" type="tns:childBType" minOccurs="0" maxOccurs="unbounded"></element>
   </choice>
 </complexType>
 <unique name="childB.max.once">
   <selector xpath="./tns:childB"></selector>
   <field xpath="@value"></field>
 </unique>
</element>

Below is one of valid XML (order of B doesn't matter or B can be excluded)

<tns:root xmlns:tns=" ">
 <tns:childA></tns:childA>
 <tns:childB></tns:childB>
 <tns:childA></tns:childA>
 <tns:childA></tns:childA>
</tns:root>

However the below one is invalid

<tns:root xmlns:tns=" ">
 <tns:childB></tns:childB>
 <tns:childA></tns:childA>
 <tns:childB></tns:childB>
 <tns:childA></tns:childA>
 <tns:childA></tns:childA>
</tns:root>
Baski
  • 829
  • 8
  • 14
  • Sorry about the delay and thanks for trying but if I have understood this correctly ChildB nodes would have a valid "value" attribute, which I don't want, so it's not really ideal. I'll keep trying. – Dave Jan 31 '13 at 15:47
  • @Dave XML instance need not have the attribute and it resides just in the xml schema. I couldnt think of other solutions either. – Baski Feb 03 '13 at 04:37
  • Hmm. The XML *need* not have the attribute, but if it did it would validate correctly, which is sort of messy. Or have I still misunderstood? – Dave Feb 04 '13 at 09:10