简体   繁体   中英

Can XML Schema specify co-occurrence constraints?

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.

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')"/>

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>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM