XSD Design - One or more rule - xsd

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>

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>

maxOccurs restriction based on node attribute in XML

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.

Vectors of a complex type

Is there a way to define the cardinality of a type at the place where that type is referenced?
<xs:complexType name="xyType">
<xs:element name="xy" maxOccurs="1">
<xs:choice maxOccurs="1" minOccurs="0">
<xs:complexType>
<xs:choice maxOccurs="unbounded" minOccurs="0">
...
</xs:choice>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
So for instance I have two types A and B that have elements that reference this type, but in one case I only allow one xy (like above) and another I would like to allow multiple xy (like if I change the maxOccurs above for xy to "unbounded").
I don't want to have to completely separate complexType definitions for xyType (single) and xyType (unbounded), because in reality the definition for this type is very long and complex.
If possible I would also like to not define too many types (like separating the inner complexType from the body and having two types referencing that type). This would also be very complex in my specific scenario (I have a complex class hierarchy that I try to define with a schema, so everything is bloated already).
So basically I'm looking for something where the type that is referencing this type is taking care about the cardinality if that makes sense at all.
I would suggest that you modularize the parts of xyType as best as possible for sharing across two types, say xyType_A that allows only one xy and xyType_B that allows an unbounded number of xys. (Of course choose semantically appropriate names rather than these stand-ins.)
For example, xyType_A and xyType_B could differ in their definitions of xy's cardinality yet share the complex machinery defined in commonType:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="xyType_A">
<xs:sequence>
<xs:element name="xy" type="commonType" maxOccurs="1"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="xyType_B">
<xs:sequence>
<xs:element name="xy" type="commonType" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="commonType">
<xs:choice maxOccurs="1" minOccurs="0">
<xs:sequence>
<xs:choice maxOccurs="unbounded" minOccurs="0">
<!-- further complicated structures continue here -->
</xs:choice>
<!-- and here or wherever -->
</xs:sequence>
</xs:choice>
</xs:complexType>
</xs:schema>
The principle (if not the magnitude of opportunity) would be the same if the elements of varying cardinality are deeper in the definitional hierarchy: Factor as much of the common definitional components as possible, and reuse those in the distinctly defined types.
This wouldn't work in XSD 1.0. You could use Schematron (on top of the XSD 1.0); it would work with no issues.
It is possible in XSD 1.1. It would require a bit of work, at least based on my understanding. The solution is to use assertions; however, they seem to be supported for complex and simple types only, which means you may still need to introduce two new types specific to element A and B; however, they would simply be extending xyType (100% reuse), for the purpose of providing a place to define the assertion specific to A and B.
If you're interested in either alternative, tag the question appropriately.

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>

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.

Resources