Reputation: 973
Using XSD, I want to define a complex element which can appear in three different forms:
<Scope Name="foo" /> <!-- no children -->
<Scope Name="foo" Src="bar" /> <!-- When Src is present, there must be no children! -->
<Scope Name="foo"><!-- other children --></Scope>
In the third case, it is well defined what may appear as children elements (e.g. all three types of "Scope"). The important part is that a Scope element with a "Src" attribute must be empty!
Furhtermore, in different places, I want only specific types of elements allowed. For example, inside the root tag, I want to allow exactly one Scope element of the third type; in most cases I wand to allow all cases. And that's the problem: How to solve this?
What I did so far: I created a complex type for each of the 3 cases which I can use within . However, I can't use:
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="Scope" type="type_Scope_WithSrc" />
<xs:element name="Scope" type="type_Scope_WithContent" />
<xs:element name="Scope" type="type_Scope_Base" />
</xs:choice>
I tried to create a union of those, but unions are only allowed for simpleTypes.
I also tried to define an overall type "type_Scope" which uses xs:choice to include them. But xs:choice would include xs:elements which would also require a name in this case :-(
Can you tell me how I can handle this?
Please do not tell me that it is not possible with XSD :-( :-(
Thank you
Regards divB
Upvotes: 2
Views: 565
Reputation: 21658
You may get different answers, depending on whether you want to achieve this with XSD 1.1 or XSD 1.0; I would assume that you're after a 1.0 solution, which I will describe here (I don't believe 1.1 is practical yet).
If you want to preserve the element name, and vary its content, your only option here is to employ xsi:type. Instead of a choice, just use a single Scope element; make its type a complex type, with an attribute named "Name". Have the other two types extend from this base type. And you're done.
Note: I used a base abstract type as a mechanism to inform people that other types are expected to go in there; reality is it'll work even without it, by using a type_Scope_Base right from the beginning.
XSD:
<?xml version="1.0" encoding="utf-8" ?>
<xsd:schema targetNamespace="http://tempuri.org/XMLSchema.xsd"
elementFormDefault="qualified"
xmlns="http://tempuri.org/XMLSchema.xsd"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:complexType name="type_Scope_BaseA" abstract="true">
</xsd:complexType>
<xsd:complexType name="type_Scope_Base">
<xsd:complexContent>
<xsd:extension base="type_Scope_BaseA">
<xsd:attribute name="Name" type="xsd:string"/>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="type_Scope_WithSrc">
<xsd:complexContent>
<xsd:extension base="type_Scope_Base">
<xsd:attribute name="Src" type="xsd:string"/>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="type_Scope_WithContent">
<xsd:complexContent>
<xsd:extension base="type_Scope_Base">
<xsd:sequence>
<xsd:any maxOccurs="unbounded" namespace="##other" processContents="lax"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:element name="root">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="Scope"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="Scope" type="type_Scope_BaseA"/>
</xsd:schema>
These are three sample XMLs, all valid. The first one with content model from type_Scope_Base
.
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!-- Sample XML generated by QTAssistant (http://www.paschidev.com) -->
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org/XMLSchema.xsd">
<Scope xsi:type="type_Scope_Base" Name="Name1"/>
</root>
This with content model from type_Scope_WithSrc
.
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!-- Sample XML generated by QTAssistant (http://www.paschidev.com) -->
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org/XMLSchema.xsd">
<Scope xsi:type="type_Scope_WithSrc" Name="Name1" Src="Src1"/>
</root>
And this with content model from type_Scope_WithContent
.
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!-- Sample XML generated by QTAssistant (http://www.paschidev.com) -->
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org/XMLSchema.xsd">
<Scope xsi:type="type_Scope_WithContent" Name="Name1">
<me:hello.you xmlns:me="http://paschidev.com"/>
</Scope>
</root>
If you want to allow for variation in the tag name, instead of a choice you could place there the head of a substitution group, which could at least give you a solution without xsi:type.
And then there are XSD 1.1 based solutions, but I would stay away from anything like that in an open environment; not everyone today has a compliant processor, let alone the spec itself is not a recommendation yet.
Upvotes: 2