I want to validate polymorphic Shape
elements, differentiated by the Type
child element (not attribute) value. Below are sibling Circle and Rectangle Shape
elements. Circles have a Radius
and only 1 Point
. Rectangles don't have Radius
and have 4 Point
elements:
<?xml version="1.0" encoding="UTF-8" ?>
<Shapes>
<Shape>
<Type>Circle</Type>
<ID>A1234</ID>
<Label>This is round</Label>
<Radius>5.4</Radius>
<Points>
<Point>
<X>5.00</X>
<Y>2.00</Y>
</Point>
</Points>
</Shape>
<Shape>
<Type>Rectangle</Type>
<ID>B4567</ID>
<Label>This is not round</Label>
<Points>
<Point>
<X>0.00</X>
<Y>0.00</Y>
</Point>
<Point>
<X>4.00</X>
<Y>0.00</Y>
</Point>
<Point>
<X>4.00</X>
<Y>2.00</Y>
</Point>
<Point>
<X>0.00</X>
<Y>2.00</Y>
</Point>
</Points>
</Shape>
</Shapes>
Here's a NON-functional schema along the lines of what I was hoping to do:
<xsd:simpleType name="ShapeTypeEnum">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="Circle"/>
<xsd:enumeration value="Rectangle"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="ShapeBase">
<xsd:sequence>
<xsd:element name="Type" type="ShapeTypeEnum"/>
<xsd:element name="ID" type="xsd:string"/>
<xsd:element name="Label" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="Shape" type="Circle">
<xsd:complexContent>
<xsd:extension base="ShapeBase">
<xsd:all>
<xsd:element name="Radius" type="xsd:decimal"/>
<xsd:element name="Points">
<xsd:complexType>
<xsd:sequence>
<xsd:element minOccurs="1" maxOccurs="1" name="Point" type="Point"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:all>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="Shape" type="Rectangle">
<xsd:complexContent>
<xsd:extension base="ShapeBase">
<xsd:all>
<xsd:element name="Points">
<xsd:complexType>
<xsd:sequence>
<xsd:element minOccurs="4" maxOccurs="4" name="Point" type="Point"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:all>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="Point">
<xsd:all>
<xsd:element name="X" type="xsd:decimal"/>
<xsd:element name="Y" type="xsd:decimal"/>
</xsd:all>
</xsd:complexType>
The lines <xsd:complexType name="Shape" type="Rectangle">
and <xsd:complexType name="Shape" type="Circle">
don't work. Is it possible to validate identically named elements with different schema sections based on the value of a child Element (Type
)?
In XSD 1.0, it can't be done. In XSD 1.1, it can, using assertions.
Though even using assertions, it's not that easy (it would be much easier if Type
were an attribute). You need to define a content model that's effectively a union of all the different models for different shapes (you can't use a simple xs:choice
in this example because it would violate UPA), and then you need to define assertions like
<xs:assert test="exists(radius) = (type = 'Circle')"/>
<xs:assert test="count(points) = 4 or type != 'Rectangle'"/>
XSD 1.1 is supported in Altova, Saxon, and Xerces, but not for example by the Microsoft schema processor.