Attribute mutex

From W3C Wiki

Attribute mutex (a co-constraint use case)

Provide for mutual exclusion of attributes (if one appears, the other must not).

Cf. Value-equals_test_required (in which the required/optional/forbidden status of one attribute depends not on the absence but on the presence another attribute but on its specific value), and Simple attribute implication (in which the legality of the one attribute depends on the presence rather than the absence of the other attribute)

source: David Carlisle (in the process of recasting OpenMath DTD into XML Schema and RelaxNG) [1]


Other use cases: Co-constraint Use Cases

Description

   The "Float" element has two attributes, taking either a hex or decimal
   value. You have to have exactly one of these present.
   If it were child elements rather than attributes I'd use xsd:choice
   and if it were simple types rather than attributes I could use a union
   but it seems that both of these constructs are not available here.
   Unless I missed something (which is quite possible) so the question:
   Is it possible to change the following so that 
   `<OMF/>` and `<OMF dec="2" hex="F"/>`
   do not validate?


    <!-- should derive from double not string, and if possible require exactly one of the hex and dec attributes -->
    <xs:element name="OMF">
       <xs:complexType>
        <xs:attribute name="dec" type="omDecFloat" use="optional" />
        <xs:attribute name="hex" type="omHexFloat" use="optional" />
        </xs:complexType>
    </xs:element>
    
    <xs:simpleType name="omDecFloat" >
        <xs:restriction base="xs:string">
        <xs:pattern value="(-?)([0-9]+)?(\.[0-9]+)?(e([+-]?)[0-9]+)?" />
        </xs:restriction>
    </xs:simpleType> 
    
    <xs:simpleType name="omHexFloat">
        <xs:restriction base="xs:string">
        <xs:pattern value="[0-9A-F]+" />
        </xs:restriction>
    </xs:simpleType> 


Analysis

(Add your analysis here; see your name in pixels!)

Possible solutions

Relax NG

Grammaticalization

If we allow Relax-style grammaticalization of attributes, then this use case can be solved this way:

 <xsd:element name="OMF">
  <xsd:complexType>
   <xsd:choice>
    <xsd:attribute name="dec" type="omDecFloat" use="required" />
    <xsd:attribute name="hex" type="omHexFloat" use="required" />
   </xsd:choice>
  </xsd:complexType>
 </xsd:element>

Schematron

Check clause

A simple check-clause approach:

 <xsd:element name="OMF">
  <xsd:annotation><xsd:appinfo><sch:pattern><sch:rule>
      <sch:assert test="(./@dec or ./@hex) and not(./@dec and ./@hex)">
       One of 'dec' or 'hex' must occur, but not both.
      </sch:assert>
     </sch:rule></sch:pattern></xsd:appinfo></xsd:annotation>
  <xsd:complexType>
   <xsd:attribute name="dec" type="omDecFloat" use="optional" />
   <xsd:attribute name="hex" type="omHexFloat" use="optional" />
  </xsd:complexType>
 </xsd:element>

SchemaPath

If we allow xsd:alt to contain an anonymous type, then we can capture this constraint thus:

 <xsd:element name="OMF">
  <xsd:alt cond="./@dec and ./@hex" type="xsd:error"/>
  <xsd:alt cond="not(./@dec) and not(./@hex)" type="xsd:error"/>
  <xsd:alt>
   <xsd:complexType>
    <xsd:attribute name="dec" type="omDecFloat" use="optional" />
    <xsd:attribute name="hex" type="omHexFloat" use="optional" />
   </xsd:complexType>
  </xsd:alt>
 </xsd:element>

Conditional Type