I was recently confronted with an interesting problem where I was asked to design a BizTalk schema which contained a complex type that must contain at least one instance of some of its child elements or optionally some or all of them. Upon questioning the business requirement it turned out that I didn’t actually have to enforce this in the schema as this level of business logic was better served by a downstream system. However I did decide that this was an interesting enough scenario (albeit not necessarily a common or practical one) to dive into it a bit deeper and see how it could be implemented using an XSD schema. Note that while I have used BizTalk 2009 schema editors in Visual Studio 2008 to create my schemas, aside from the wording of error messages nothing in this blog post is really BizTalk specific.
Let’s assume that we are dealing with the XML structure below and we are advised that the record structure must always contain either an Element1 or an Element2 element or both (the rest of the elements are all optional).
One way we can achieve the above goal is by making use of choice structures as below.
Note that in the above screenshot the choice consisted of a sequence that contained both Element1 and an optional Element2, and a second sequence that contained only Element2. This caters for scenarios where both elements exist, or only one exist. See the below screenshots which illustrate that if either Element1 or Element2 are missing then that is not a problem but if both are missing then the XML message is invalid.
When I originally approached the problem I thought of creating a choice structure with three sequences, one with Element1, the second with Element2, and the third with Element1 and Element 2. However this is not allowed and trying to implement this will result in an error stating “Multiple definitions of element xxx causes the content model to become ambiguous…” as below.
Now what if we want to change the data type for Element2 (which exists in both of the sequences in the choice). If we try to change the data type from string to int on the Element2 element in one of the sequences using the BizTalk/Visual Studio schema editor we will get an error stating “Elements with the same name and in the same scope must have the same type” as below.
The reason for this is that the data type must be the same for elements with the same name that exists in multiple sequences in a choice structure. Changing them one at a time is not an option. One way to get around this is to open the schema using an XML editor and to change the data type for both of the Element2 elements at the same time. An even cleaner solution would be to extract the definition of Element2 into a simple type, and to have both Element2 elements use the simple type as their type so that if the data type for Element2 needed to be changed it would only have to be changed on the simple type in the future. In the below screenshot this has been done for Element1, Element2, Element3, Element4, and Element5 and we are now enabled to change data types with ease.
Now what if we wanted to add Element3 to the choice as well, the new rule stating that at least one of Element1, Element2, or Element3 are provided, or any combination of two or three of the elements are provided. This can be achieved quite easily with the below structure. Note that the pattern is to have all the elements in the first sequence where only Element1 is mandatory, then to remove Element1 in the second sequence with Element2 now being mandatory, and the third sequence only containing Element3 which is now mandatory. Adding more elements to the mix would require you to extend this pattern.
How about if Element2 is always mandatory, and you additionally also need to provide either Element1 or Element3 or both elements. You can achieve this with the below structure.
I hope that this blog post has illustrated to you how you can create schemas that specify multiple combinations of optional/mandatory rules for a given complex type through the use of choice structures with child sequence groups.
An interesting article and smart solution, Johann. Thanks for sharing!
Did you try to include Element1,2 and 3 into additional nesting record? Usually requirements like this force me to add one more layer and it helps.
LikeLike
Hi Leonid,
Thank you. Yes that is an option as well, and I was specifically avoiding it since I was designing the schema from an existing XML standard thus couldn’t introduce extra layers.
I must admit that I have not used sequences groups on their own much in the past and tend to use records to enforce sequence. I will certainly be thinking a bit more about whether I really want to use a record or not in the future (and I imagine I would in most cases).
Cheers
Johann
LikeLike
Actually the Sequence group just an unnamed record, a record without explicit tag.
LikeLike
Yes I agree, but there might well be scenarios where not introducing the extra tag might be worthwhile.
Again, I think it’s usage would be a rare case, but the way I see it is the more knowledge you have the more enabled you are to design the most appropriate solutions.
Cheers
Johann
LikeLike
Sure,
I think the Sequence group could be used more frequently in the schema development. In many cases the tag space is important and the records without tags are welcome. If developer works mostly with schemas and maps but not with the target Xml documents, the Sequence group is worth to be used.
LikeLike
Nice way of solving this business requirement! Never thought about this kind of a solution. Thanks for sharing.
LikeLike