Reputation: 6166
It is possible to add dynamic attribute in <element>
for example I have a <A>
element it have a fixed attribute name mode
<A mode="ENABLE"> <!-- ENABLE or DISABLE-->
if mode is enable then it will add some more dynamic attribute in element `<A>`
like
<A mode="ENABLE" attr1="abc" attr2="xyz">
if mode is disable then it will like this .
<A mode="DISABLE" attr3="abc" attr4="xyz">
That means attribute mode
is fixed and attr1,attr2,attr3 and attr4
depend on values of mode
attribute
mode
- Fixed attribute.
attr1,attr2,attr3 and attr4
- Dynamic attribute depend on value of mode
Please give me suitable example.
Upvotes: 1
Views: 3248
Reputation: 23627
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.
Upvotes: 1