views:

154

answers:

2

Can an XML Schema document specify that two items must co-occur?

For example, that there are two optional elements, and they are either both present or both absent.

a b? c d? e      # giving only {ace, abcde}
                 # instead of all combinations: {ace, acde, abce, abcde}

<element name="root">
  <complexType>
    <sequence>
      <element ref="a"/>
      <element ref="b" minOccurs="0"/>
      <element ref="c"/>
      <element ref="d" minOccurs="0"/>
      <element ref="e"/>
    <sequence>
  <complexType>
<element>

Another example: that there are two repeated elements, and that however many times the first one occurs, the second also occurs that many times:

a b^n c d^n e  # where ^n is a superscript denoting number of repeats
               # giving {ace, abcde, abbcdde, abbbcddde, ...}
               # but no other combinations

<element name="root">
  <complexType>
    <sequence>
      <element ref="a"/>
      <element ref="b" minOccurs="0" maxOccurs="unbounded"/>
      <element ref="c"/>
      <element ref="d" minOccurs="0" maxOccurs="unbounded"/>
      <element ref="e"/>
    <sequence>
  <complexType>
<element>

Maybe there's something in the identity constraints in the XML Schema spec, but that seems to be about getting exactly one instance with a certain characteristic, rather than ensuring two have the same characteristic.

A: 

Not sure about the ability to do it directly. A simple option though would be to embed them in a single optional element and have each element of the new element be required. Something along the lines of:

<element name="root">
<complexType>
<sequence>
<element ref="a"/>
<element ref="c"/>
<element ref="f" minOccurs="0">
<complexType>
<element ref="b" minOccurs="1"/>
<element ref="d" minOccurs="1"/>
</complexType>
</element>
<element ref="e"/>
<sequence>
<complexType>
<element>

Matt
Thanks, yes, that works for the special case where the elements are adjacent; although for repetitions, you get bdbdbd... instead of bbbddd. BTW: I think you mean that <element ref="f" minOccurs="0"><complexType> to be a model group <sequence minOccurs="0">.
13ren
Also, for repeated adjacent elements, a context free grammar can do it with recursion (A --> b A d), but this is explicitly disallowed for model groups by the spec (recursion must have an element nested in it). That's just an aside, I'm interested co-occurrence in general, including non-adjacent elements. I don't think there's a way to do it in XML Schema, but some clever person might have worked out a way (maybe with nested keyrefs...?)
13ren
+2  A: 

Co-occurrence is one of the things that the existing 1.0 Schema spec can't address. This is one of the reasons why Schematron was released. Assertion based validation can handle this case, along with any other that can be expressed via an XPath express rather easily.

Furthermore, in the 1.1 Schema spec there is assertion functionality, but I'm not aware of widespread processor support for 1.1 yet.

The classic example that assertion based validation usually revolves around a credit card transaction, for example:

<card>
  <number>1111-1111-1111</number>
  <type>mastercard</type>
</card>

Here we want to make sure that mastercard numbers start with '1' and visa starts with '2' (not the real convention, of course). There's no way to do that with Schema 1.0, but rather easy via an assertion (in pseudo-code)

<assert test="starts-with(card/type[.='mastercard'],'1')"/>
16bytes