Reputation: 2063
in my XML file a "MultipleChoice" node defined in the following way:
<multipleChoice numberOfChoices="" percentage="0"> text
corresponding to the needs of my XSD schema, my XSD definition of the mentioned is the following one:
<xs:element name="multipleChoice" type="MultipleChoiceType"/>
<xs:complexType name="MultipleChoiceType" mixed="true">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="choice"/>
</xs:sequence>
<xs:attribute name="numberOfChoices" type="xs:integer" use="required"/>
<xs:attribute name="percentage" type="xs:integer" use="required"/>
<xs:assert test="count(./choice) = @numberOfChoices" />
</xs:complexType>
What I need is to add another restriction to my "percentage" attribute:
For example: if "numberOfChoices"="3" then in "percentage" we need 3 integers, separated by only one white space, for example "percentage"= "30 40 30".
In case in the "actor" attribute there is something else than the string "Me", we don't care what's happening in the "numberOfChoices" and "percentage" attributes.
I need the "percentage" attribute to be required and I need that the following situation is accepted as well:
<multipleChoice actor="" bar="" points="0" numberOfChoices="3" percentage="">
Since in the "actor" attribute there is not the string "Me" I don't have to check what's in the "percentage" attribute. But it has to be there anyway.
Upvotes: 2
Views: 337
Reputation: 6016
First of all, in your example percentage
is a xs:int
attribute, you need to change it to a xs:int
list (and/or add a regex if you really need only one withespace between values).
Then you can use xpath tokenize function to divide and count percentage value (example: tokenize('1 2 3 4 5', '\s') returns ('1', '2', '3', '4', '5').
Example schema:
<?xml version="1.0" encoding="UTF-8"?>
<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="multipleChoice" type="MultipleChoiceType"/>
<xs:complexType name="MultipleChoiceType" mixed="true">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="choice" type="xs:string"/>
</xs:sequence>
<xs:attribute name="numberOfChoices" type="xs:integer" use="required"/>
<!-- Percentage is now a list of xs:int -->
<xs:attribute name="percentage" use="required">
<xs:simpleType>
<xs:list itemType="xs:integer"/>
</xs:simpleType>
</xs:attribute>
<!-- New actor attribute -->
<xs:attribute name="actor" type="xs:string" use="required"/>
<xs:assert test="count(./choice) = @numberOfChoices" />
<!-- The count only needs to be satisfied if actor=Me -->
<xs:assert test="@actor != 'Me' or count(tokenize(normalize-space(string(@percentage)),'\s')) = @numberOfChoices"/>
</xs:complexType>
</xs:schema>
Note that I've used normalize-space xpath function function because ' 1 2 3'
is a valid xs:int
list (if you want you could use a regex instead).
Upvotes: 1