maxOccurs restriction based on node attribute in XML - xsd

I have following XSD:
<xs:element name="constGroup">
<xs:complexType>
<xs:sequence>
<xs:element name="const" maxOccurs="unbounded">
</xs:element>
</xs:sequence>
<xs:attribute name="activateBitmask" type="xs:boolean" use="required"/>
</xs:complexType>
</xs:element>
This describes a group of constants that may have a bitmask. As I have a 32-bit integer in the underlying program I need to restrict the occurences of <const> to 32 when the attribute activateBitmask of the parent is set to true. I cannot set it hard to 32 because there are some groups of constants without bitmask that count more than 32 members.

Related

Ambiguous Content Model - Allowing Individual Elements or specific combinations but not all elements

Hopefully the schema here describes what I'm trying to do.
<xs:complexType name="Survey">
<xs:sequence>
<xs:element name="SurveyID" type="SurveyID"/>
<xs:choice>
<!-- Allow topics, questions, answers on their own -->
<xs:element name="Topics" type="SurveyTopics"/>
<xs:element name="Questions" type="SurveyQuestions"/>
<xs:element name="Answers" type="SurveyAnswers"/>
<xs:sequence>
<!-- Allow topics and questions to be created simultaneously by a survey admin -->
<xs:element name="Topics" type="SurveyTopics"/>
<xs:element name="Questions" type="SurveyQuestions"/>
</xs:sequence>
<xs:sequence>
<!-- Allow user to create new questions when they're answering -->
<xs:element name="Questions" type="SurveyQuestions"/>
<xs:element name="Answers" type="SurveyAnswers"/>
</xs:sequence>
</xs:choice>
</xs:sequence>
</xs:complexType>
I want to accept topics, questions, and answers. Topics and questions can be combined, a survey administrator might do this when creating new topics. Questions and answers can be combined, a surveyee is allowed to add their own questions when filling out the survey.
The error I'm getting is Multiple definition of element '..Topics' causes the content model to become ambiguous. I think this is because it's not sure if Topics is on it's own, or supposed to be the start of the sequence.
Is there good way to accomplish what I'm going for?
After posting I found a related question that pointed me in the right direction.
This is what I came up with.
<xs:complexType name="Survey">
<xs:sequence>
<xs:element name="SurveyID" type="SurveyID"/>
<xs:choice>
<xs:sequence>
<!-- Allow topics, or topics and questions -->
<xs:element name="Topics" type="SurveyTopics"/>
<xs:element name="Questions" type="SurveyQuestions" minOccurs="0"/>
</xs:sequence>
<xs:sequence>
<!-- Allow questions, or questions and answers -->
<xs:element name="Questions" type="SurveyQuestions"/>
<xs:element name="Answers" type="SurveyAnswers" minOccurs="0"/>
</xs:sequence>
<!-- Allow answers on their own -->
<xs:element name="Answers" type="SurveyAnswers"/
</xs:choice>
</xs:sequence>
</xs:complexType>

Cannot figure out a way to create XML schema that matches random order items with conditions

We're trying to find a way to have a schema that would validate certain rules, but we've tried various combinations of xs:all, xs:choice, xs:group and xs:sequence with no success. The rules are basically this:
only one occurance of the LICAPPIN01 element should occur
only one occurance of the LICAPPIN99 element should occur
there should be the same number of LICAPPIN30 and LICAPPIN31
there should be the same number of LICAPPIN40 and LICAPPIN41
there needs to be at least one set of LICAPPIN30/31 or LICAPPIN40/41 (both can be there as well)
For all of the above, the order does not matter -- any order is acceptable
The simplest schema we tried is this:
<?xml version="1.0" standalone="yes"?>
<xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="NewDataSet">
<xs:complexType>
<xs:choice minOccurs="1" maxOccurs="unbounded">
<xs:element name="LICAPPIN01" minOccurs="1" maxOccurs="1">
</xs:element>
<xs:element name="LICAPPIN30" minOccurs="1" maxOccurs="unbounded">
</xs:element>
<xs:element name="LICAPPIN31" minOccurs="1" maxOccurs="unbounded">
</xs:element>
<xs:element name="LICAPPIN40" minOccurs="1" maxOccurs="unbounded">
</xs:element>
<xs:element name="LICAPPIN41" minOccurs="1" maxOccurs="unbounded">
</xs:element>
<xs:element name="LICAPPIN99" minOccurs="1" maxOccurs="1">
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
This has a number of problems:
it allows multiple LICAPPIN01 and LICAPPIN99 (replacing with xs:all might fix this?)
it does not enforce rule 3 and 4
for rule 5, it seems to force both LICAPPIN30/31 and LICAPPIN40/41 when it should be possible to only have one of the two sets
We also tried a more complex approach with xs:group for LICAPPIN30/31 and for LICAPPIN40/41 but it broke rule 6.
Any idea if this is even possible to meet all of our basic rules? In a relatively simple Schema. In the example above, I removed all of the details within each LICAPPINnn elements -- they each contain complex types, and we don't want to have to duplicate these in multiple places, ideally.
Thanks,
Denis
It's not easy to write a content model to meet all your requirements, but it's easy to meet all but the last.
If variation in the order of elements is essential to convey necessary information, then your best bet is to use assertions in XSD 1.1 or Schematron. If variation in the order of elements conveys no information, then you have the option of declaring that variation in order is not a requirement after all. The vocabulary design authorities I respect most highly say pretty consistently that if the sequence of children does not convey information, then there is no reason not to fix it.
Here is a content model that meets all the requirements you list except the last one:
<xs:complexType>
<xs:sequence>
<xs:element name="LICAPPIN01"/>
<xs:choice maxOccurs="unbounded">
<xs:sequence>
<xs:element name="LICAPPIN30"/>
<xs:element name="LICAPPIN31"/>
</xs:sequence>
<xs:sequence>
<xs:element name="LICAPPIN40"/>
<xs:element name="LICAPPIN41"/>
</xs:sequence>
</xs:choice>
<xs:element name="LICAPPIN99"/>
</xs:sequence>
</xs:complexType>

Constraint or Restriction on xsi:type

This is a generalized example of what I am up against.
I have created derived types in my schema and want to create an element which is an unbounded list (sequence) which has a restrictition where only two of the three derived types is allowed.
To say it from a top level view, "I have events where in one situation can only have two types of events".
Here is how I have defined my events and a subsequent holder of the sequence. (This all works and is valid).
The abstract item is a complex type named "Event Base" and has a common attribute called Name:
<xs:complexType name="EventBase">
<xs:annotation><xs:documentation>***Abstract Event***</xs:documentation></xs:annotation>
<xs:attribute name="Name"/>
</xs:complexType>
Then I have three events derived from the abstract as follows
<xs:complexType name="DerivedEvent1">
<xs:complexContent>
<xs:extension base="EventBase">
<xs:attribute name="Alpha" type="xs:string"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="DerivedEvent2">
<xs:complexContent>
<xs:extension base="EventBase">
<xs:attribute name="Beta"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="DerivedEvent3">
<xs:complexContent>
<xs:extension base="EventBase">
<xs:attribute name="Gamma"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
To facilliate a complex object to hold the derived events, I create a concrete "generic" event derived from the abstract complex
<xs:element name="Event" type="EventBase">
<xs:annotation><xs:documentation>A generic event derived from abstract.</xs:documentation></xs:annotation>
</xs:element>
Then I want to be able to hold the events, so I create a new complex object to hold the "generic" event shown above, but will actually hold derived events by the eventual consumer.
<xs:complexType name="EventsCollectionType">
<xs:annotation><xs:documentation>Holds derived events</xs:documentation></xs:annotation>
<xs:sequence>
<xs:element ref="Event" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
Finally I create an element derived from the collection type which will hold actual events:
<xs:element name="Events"><xs:annotation><xs:documentation>Concrete holder of events.</xs:documentation></xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element ref="Event" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
The resulting xml looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<Events xsi:noNamespaceSchemaLocation="file:///C:/StackOverflow.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Event xsi:type="DerivedEvent1" Name="D1" Alpha="Content1"/>
<Event xsi:type="DerivedEvent3" Name="D1" Gamma="Content3"/>
</Events>
So the question is, how can I create a final Event*s* element which will hold only specific xsi:typed items?
So in the case where a restriction held that only the derived types of 1 and 3 would be valid (as above); but if it had a derived type 2 it would be invalid.
I have created a public GIST (Constraint or Restriction on xsi:type)
I may be wrong, but I don't think this is possible.
Within the Events collection you essentially want to have different structures but all with the same element name "Event". This goes against a fundamental constraint of schemas: http://www.w3.org/TR/xmlschema-1/#cos-element-consistent. Using xsi:type gives the schema processor a hint that will allow it to disambiguate this choice of structures thus avoiding violating this rule. It's essentially a work-around.
Could you not call each different things so you have a collection of "event1"s and "event3"s or an outer collection containing a sequence of optional "events1"s and "event3"s? It would be much easier to schema enforce the structure in this way. Also then you wouldn't require to use xsi:type at all. I'm not sure if you are using xsi:type in your instances to try to work around this limitation or for another reason but it may be easier for anybody using the schema to not have to worry about derived types.
Alternatively, you could potentially use another technology (eg schematron) to help enforce this constraint.

Any difference when you use min/maxOccurs at sequence rather than element level

What I mean is are there any situations where this:
<xs:element name="MyType1">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="MyType2">...</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
has a different meaning to this:
<xs:element name="MyType1">
<xs:complexType>
<xs:sequence maxOccurs="unbounded">
<xs:element name="MyType2">...</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
Thanks in advance
Generally speaking occurrence constraints (minOccurs or maxOccurs) on element groups (sequences or choices) mean that the whole group can be repeated whereas occurrence constraints on elements mean that the element can be repeated before the next element in the group appears.
If your sequence contains only one element, there is no difference.
<xs:sequence>
<xs:element maxOccurs="unbounded" name="MyType2">...</xs:element>
</xs:sequence>
is equal to
<xs:sequence maxOccurs="unbounded">
<xs:element name="MyType2">...</xs:element>
</xs:sequence>
and they both allow repeating the element <MyType2>. There will be a difference as soon as the sequence contains more than one element definition.
<xs:sequence>
<xs:element maxOccurs="unbounded" name="MyType">...</xs:element>
<xs:element maxOccurs="unbounded" name="foobar">...</xs:element>
</xs:sequence>
is not equal to
<xs:sequence maxOccurs="unbounded">
<xs:element name="MyType">...</xs:element>
<xs:element name="foobar">...</xs:element>
</xs:sequence>
The first one allows structures like
<MyType/>
<MyType/>
<foobar/>
<foobar/>
but the second one doesn't allow such a structure. Instead it allows structures like
<MyType/>
<foobar/>
<MyType/>
<foobar/>
which on the other hand are not allowed by the first definition.

XSD Design - One or more rule

I am designing a new XSD to capture points information from a business partner. For each transaction the partner must provide a value of points for at least one points type. I have the following:
<xs:element name="Points">
<xs:complexType>
<xs:sequence>
<xs:element name="SKUPointsQty" type="xs:int" minOccurs="0"/>
<xs:element name="WelcomePointsQty" type="xs:int" minOccurs="0"/>
<xs:element name="ManualPointsQty" type="xs:int" minOccurs="0"/>
<xs:element name="GreenPointQty" type="xs:int" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
The business rules are:
a transaction must provide points from one or more of the points type
a transaction cannot provide more than one instance of the same points type
What I have so far is not ideal because it would be possible to provide an XML instance without any points. I can't use a choice element because it must be possible to provide an XML instance with more that one points type element. The same point type must not be repeated for a single transaction.
Is it possible to enforce this rule in the design of the XSD?
I have a copy of the excellent XML Schema Companion by Neil Bradley. I can't find the answer in there so I guess it's not possible but thought I'd share the puzzle!
Thanks
Rob.
I think this kind of constraint logic is beyond XSD. Here are three techniques for checking instance documents for constraints that are not expressable by XML Schemas.
* a transaction cannot provide more than one instance of the same
points type
That's fairly easy - and you already have that, basically.
Since your "inner" elements like
<xs:element name="ManualPointsQty" type="xs:int" minOccurs="0"/>
are defined as they are, you make them optional (minOccurs="0"), and by default since you didn't specify anything else, they also have a maxOccurs="1" setting.
So that half of the requirements should be taken care of.
a transaction must provide points from one or more of the points
type
That's the part where XML schema is not helping you much - you cannot express requirements like this in XSD. XSD only lends itself to "structural" modelling - things like "include this", "include 1 through 5 of these" - but you cannot express limitations that "span" more than one element like "if A is present, then B cannot be present", or "if A is present, then the value of B must be between 10 and 100". The "at least one of the four types must be present" also falls into that category, unfortunately :-( No luck there.
Since its a sequence, could you have a choice of four forms, depending on the first element present?
<xs:element name="Points">
<xs:complexType>
<xs:choice>
<xs:sequence>
<xs:element name="a" type="xs:int" />
<xs:element name="b" type="xs:int" minOccurs="0"/>
<xs:element name="c" type="xs:int" minOccurs="0"/>
<xs:element name="d" type="xs:int" minOccurs="0"/>
</xs:sequence>
<xs:sequence>
<xs:element name="b" type="xs:int" />
<xs:element name="c" type="xs:int" minOccurs="0"/>
<xs:element name="d" type="xs:int" minOccurs="0"/>
</xs:sequence>
<xs:sequence>
<xs:element name="c" type="xs:int" />
<xs:element name="d" type="xs:int" minOccurs="0"/>
</xs:sequence>
<xs:sequence>
<xs:element name="d" type="xs:int" />
</xs:sequence>
</xs:choice>
</xs:complexType>
</xs:element>

Resources