To allow attributes depending on the contents of other attributes you need XSD 1.1 (or some XSD 1.0 extension such as Schematron). In XSD 1.1 you can use an assertion xs:assert
where you declare the rules for the complex type using XPath.
To validate this instance:
<modes>
<A mode="ENABLE" attr1="abc" attr2="xyz" />
<A mode="DISABLE" attr3="abc" attr4="xyz" />
</modes>
You can use a XSD like the one below:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" vc:minVersion="1.1">
<xs:element name="modes">
<xs:complexType>
<xs:sequence>
<xs:element ref="A" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:attributeGroup name="enabled-attributes">
<xs:attribute name="attr1" type="xs:string" use="optional"/>
<xs:attribute name="attr2" type="xs:string" use="optional"/>
</xs:attributeGroup>
<xs:attributeGroup name="disabled-attributes">
<xs:attribute name="attr3" type="xs:string" use="optional"/>
<xs:attribute name="attr4" type="xs:string" use="optional"/>
</xs:attributeGroup>
<xs:element name="A">
<xs:complexType>
<xs:attributeGroup ref="disabled-attributes"/>
<xs:attributeGroup ref="enabled-attributes"/>
<xs:attribute name="mode" use="required">
<xs:simpleType>
<xs:restriction base="xs:NMTOKEN">
<xs:enumeration value="ENABLE" />
<xs:enumeration value="DISABLE" />
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:assert test="(@mode='ENABLE' and @attr1 and @attr2 and not(@attr3) and not(@attr4))
or (@mode='DISABLE' and @attr3 and @attr4 and not(@attr1) and not(@attr2))"/>
</xs:complexType>
</xs:element>
</xs:schema>
I placed the attributes for each mode in a separate attribute group. Your mode
attribute is not actually fixed
but can have two values, so I used an enumeration to restrict it to those two values.
The line that requires XSD 1.1 is the xs:assert
line. The XPath expression is evaluated relative to the elements in the complex type. If the expression is true, it will validate.
Validation will fail otherwise. These A
nodes will both fail validation:
<modes>
<A mode="DISABLE" attr1="fgs" attr4="hjs" />
<A mode="ENABLE" attr3="fgs" attr4="hjs" />
</modes>
Update: I added the not()
clauses above, since the assertion was incomplete as you noted. Now this validates to false:
<A mode="DISABLE" attr1="fgs" attr2="hjs" attr3="fgs" attr4="fgs"/>
You can also use other criteria (it's a XPath subset), such as the number of attributes, for example if you have a lot of attributes and want to avoid a lot of not()
clauses you can use:
@mode='ENABLE' and @attr1 and @attr2 and count(@*) = 3
that will restrict the total number of attributes to 3.