Suppose I want to model a <Product>
. A product can either have variants (e.g. a T-shirt that comes in different colours), or have a single variant, like a sweater that only comes in one colour.
I want to make a schema that allows for both of these syntaxes to be valid:
<MyXMLDoc>
<Product>
<Variants>
<Variant>
<Name>Red T-Shirt</Name>
<Description>A red t-shirt</Description>
</Variant>
<Variant>
<Name>Green T-Shirt</Name>
<Description>A green t-shirt</Description>
</Variant>
<Variant>
<Name>Blue T-Shirt</Name>
<Description>A blue t-shirt</Description>
</Variant>
</Variants>
</Product>
<Product>
<Name>Black sweater</Name>
<Description>A plain ol' black sweater</Description>
</Product>
</MyXMLDoc>
The closest I could get was:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="MyXMLDoc">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" ref="Product"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Product">
<xs:complexType>
<xs:choice>
<xs:element ref="Variant"/>
<xs:element ref="Variants"/>
</xs:choice>
</xs:complexType>
</xs:element>
<xs:element name="Variants">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" ref="Variant"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Variant">
<xs:complexType>
<xs:sequence>
<xs:element ref="Name"/>
<xs:element ref="Description"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Name" type="xs:string"/>
<xs:element name="Description" type="xs:string"/>
</xs:schema>
The xs:choice
between a <Variant>
or <Variants>
allows me to get rid of the <Variants>
level of nesting, but the <Name>
and <Description>
still need to be parented under a single <Variant>
.
Is there a way to tell an XML-schema to expect either an element (<Variant>
), or the in-lined members of an element (the <Name>
, <Description>
from within a <Variant>
, without needing to actually be wrapped in a <Variant>
)?
Notice that the <Name>
and `
I think this is what you are aiming at:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="MyXMLDoc">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" ref="Product"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Product">
<xs:complexType>
<xs:choice>
<xs:group ref="VariantGroup"/>
<xs:element ref="Variant" maxOccurs="unbounded"/>
</xs:choice>
</xs:complexType>
</xs:element>
<xs:element name="Variant">
<xs:complexType>
<xs:group ref="variantGroup"/>
</xs:complexType>
</xs:element>
<xs:group name="VariantGroup">
<xs:sequence>
<xs:element name="Name" type="xs:string"/>
<xs:element name="Description" type="xs:string"/>
</xs:sequence>
</xs:group>
</xs:schema>
I have removed the <Variants>
level because your comments seem to indicate that you want to avoid it - although your XML example does include it.
Although your suggested XML can be described using XML Schema, I think it would be simpler to represent the single-variant product like this:
<Product>
<Variant>
<Name>Black sweater</Name>
<Description>A plain ol' black sweater</Description>
</Variant>
</Product>
That would make the XML Schema much simpler - just set minOccurs=1 on the Variant element.