XML schema xs:choice inside xs:sequence

xmlxsdxsd-validation

I'm trying to use a xs:choice element, but while validating the XSD file, I'm getting an error which I suppose it's related to the xs:choice element. I've searched for this problem for quite a bit, found some similar ones, but none gave me the answer I was looking for in order to solve my problem.

What I'm trying to do is, declare an element called "data", whose childs would be a timestamp and a sensor or a provider (here is where I'm trying to use a choice element, since I only want a sensor or provider element as sibling of the timestamp).

The following XML is what I'm trying to validate:

<?xml version="1.0" encoding="ISO-8859-1"?>
<experience xmlns="http://www.w3schools.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >
<data>
    <timestamp>123456789</timestamp>
    <sensor origin="proximity" >
        <x-axis>9</x-axis>
        <y-axis>0</y-axis>
        <z-axis>0</z-axis>
        <w-axis>0</w-axis>
    </sensor>
</data>
</experience>

And in order to validate this XML, I wrote the following XSD file:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

<!-- definition of attributes -->
<xs:attribute name="origin" type="xs:string" />

<!-- definition of complex elements -->
    <xs:element name="provider">
        <xs:complexType>
            <xs:all>
                <xs:element name="latitude"  type="xs:float" />
                <xs:element name="longitude" type="xs:float" />
                <xs:element name="altitude"  type="xs:float" />
                <xs:element name="bearing"   type="xs:float" />
                <xs:element name="speed"     type="xs:float" />
            </xs:all>
            <xs:attribute ref="origin" use="required"/>
        </xs:complexType>
    </xs:element>

    <xs:element name="sensor">
        <xs:complexType>
            <xs:all>
                <xs:element name="x-axis" type="xs:float" />
                <xs:element name="y-axis" type="xs:float" />
                <xs:element name="z-axis" type="xs:float" />
                <xs:element name="w-axis" type="xs:float" />
            </xs:all>
            <xs:attribute ref="origin" use="required"/>
        </xs:complexType>
    </xs:element>

    <xs:element name="data">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="timestamp" minOccurs="1" maxOccurs="1" />

                <xs:choice>
                    <element ref="provider" />
                    <element ref="sensor" />
                </xs:choice>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

<!-- definition of main type -->
    <xs:element name="experience">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="data" minOccurs="0" maxOccurs="unbounded"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

But once I upload the file and try to validate it using the following w3 website, I get the following error:

file:/usr/local/XSV/xsvlog/tmph7cMmLuploaded:45:6: Invalid per
cvc-complex-type.1.2.4: element {None}:element not allowed here (1) in
element {http://www.w3.org/2001/XMLSchema}:choice, expecting
[{http://www.w3.org/2001/XMLSchema}:annotation,$,{http://www.w3.org/2001/XMLSchema}:element,{http://www.w3.org/2001/XMLSchema}:group,{http://www.w3.org/2001/XMLSchema}:choice,{http://www.w3.org/2001/XMLSchema}:sequence,{http://www.w3.org/2001/XMLSchema}:any]:

I think that the problem is in the xs:choice element, but I could be wrong.

Since it's the first time I'm trying to use the xs:choice element, I have some doubts whether I'm using it correctly or not. According to the example in w3schools I am, but since I intend to use it next to another element, I don't know if it's correct anymore.

If someone could help me on this one I would be very appreciated.

Many thanks in advance.

Best Answer

There are some moving targets in your XML and XSD; so the XSD and XML below are BOTH minimally modified to match each other...

Modified XSD:

<?xml version="1.0" encoding="utf-8" ?>
<!-- XML Schema generated by QTAssistant/XSD Module (http://www.paschidev.com) -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://www.w3schools.com" targetNamespace="http://www.w3schools.com" elementFormDefault="qualified">

    <!-- definition of attributes -->
    <xs:attribute name="origin" type="xs:string"/>

    <!-- definition of complex elements -->
    <xs:element name="provider">
        <xs:complexType>
            <xs:all>
                <xs:element name="latitude" type="xs:float"/>
                <xs:element name="longitude" type="xs:float"/>
                <xs:element name="altitude" type="xs:float"/>
                <xs:element name="bearing" type="xs:float"/>
                <xs:element name="speed" type="xs:float"/>
            </xs:all>
            <xs:attribute ref="origin" use="required"/>
        </xs:complexType>
    </xs:element>

    <xs:element name="sensor">
        <xs:complexType>
            <xs:all>
                <xs:element name="x-axis" type="xs:float"/>
                <xs:element name="y-axis" type="xs:float"/>
                <xs:element name="z-axis" type="xs:float"/>
                <xs:element name="w-axis" type="xs:float"/>
            </xs:all>
            <xs:attribute ref="origin" use="required"/>
        </xs:complexType>
    </xs:element>
    <xs:element name="timestamp" type="xs:long"/>

    <xs:element name="data">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="timestamp" minOccurs="1" maxOccurs="1"/>

                <xs:choice>
                    <xs:element ref="provider"/>
                    <xs:element ref="sensor"/>
                </xs:choice>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <!-- definition of main type -->
    <xs:element name="experience">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="data" minOccurs="0" maxOccurs="unbounded"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

Modified XML:

<?xml version="1.0" encoding="ISO-8859-1"?>
<experience xmlns="http://www.w3schools.com" xmlns:tns="http://www.w3schools.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <data>
        <timestamp>123456789</timestamp>
        <sensor tns:origin="proximity">
            <x-axis>9</x-axis>
            <y-axis>0</y-axis>
            <z-axis>0</z-axis>
            <w-axis>0</w-axis>
        </sensor>
    </data>
</experience>

So this is what happens:

  • your XML defines a default XML namespace; therefore, your XSD must define a matching namespace, hence see the new targetNamespace attribute and the addition of the default xmlns to match that.

  • Since all your elements are qualified (due to the use of a default namespace at the root level) then your schema should use elementFormDefault="qualified"

  • Your problem with the choice is that you have &lt;element ref="provider", etc. which needs the xs: qualifier (this is the gist of the error you've provided)

  • I've added the timestamp element in your XSD.

With these changes though, the problem now becomes your XML, particularly the origin attribute. Since you've declared the attribute global, it must be qualified in the namespace of the XSD, hence me adding the xmln:tns=... and fixin tns:origin=...

If you really don't want to change the XML, then your XSD should either define the attribute locally (instead of referencing), or wrap the attribute into a group and reference that instead. So here is an updated XSD that matches the original XML.

<?xml version="1.0" encoding="utf-8" ?>
<!-- XML Schema generated by QTAssistant/XSD Module (http://www.paschidev.com) -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://www.w3schools.com" targetNamespace="http://www.w3schools.com" elementFormDefault="qualified">
    <xs:attributeGroup name="origin">
        <!-- definition of attributes -->
        <xs:attribute name="origin" type="xs:string"/>      
    </xs:attributeGroup>

    <!-- definition of complex elements -->
    <xs:element name="provider">
        <xs:complexType>
            <xs:all>
                <xs:element name="latitude" type="xs:float"/>
                <xs:element name="longitude" type="xs:float"/>
                <xs:element name="altitude" type="xs:float"/>
                <xs:element name="bearing" type="xs:float"/>
                <xs:element name="speed" type="xs:float"/>
            </xs:all>
            <xs:attributeGroup ref="origin"/>
        </xs:complexType>
    </xs:element>

    <xs:element name="sensor">
        <xs:complexType>
            <xs:all>
                <xs:element name="x-axis" type="xs:float"/>
                <xs:element name="y-axis" type="xs:float"/>
                <xs:element name="z-axis" type="xs:float"/>
                <xs:element name="w-axis" type="xs:float"/>
            </xs:all>
            <xs:attributeGroup ref="origin"/>
        </xs:complexType>
    </xs:element>
    <xs:element name="timestamp" type="xs:long"/>

    <xs:element name="data">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="timestamp" minOccurs="1" maxOccurs="1"/>

                <xs:choice>
                    <xs:element ref="provider"/>
                    <xs:element ref="sensor"/>
                </xs:choice>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <!-- definition of main type -->
    <xs:element name="experience">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="data" minOccurs="0" maxOccurs="unbounded"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>