xmlxsd

How to define XSD element to have multiple children, all of which are simple and only have attributes?


I am trying to define a section of my XSD in which the following XML would be valid:

<machine>
    <timing offset="3s" period="20s"/>

    <!-- <machine> actually has many child elements, all of them are like <timing>
         and only have attributes -->
</machine>

Here's what I have so far:

<xs:element name="machine">
    <xs:complexType>
        <xs:all>
            <!-- Definition for the <timing> child element. -->
            <xs:element name="timing" type="timing_type"/>
            <xs:complexType name="timing_type">
                <xs:attribute name="offset" type="xs:string"/>
                <xs:attribute name="period" type="xs:string"/>
            </xs:complexType>

            <!-- Definitions for the other <machine> child elements... -->
        </xs:all>
    </xd:complexType>
</xs:element>

On the line that reads <xs:complexType name="timing_type">, I get the following error message:

Error resolving component 'timing_type'. It was detected that 'timing_type' is in namespace 'http://www.w3.org/ 2001/XMLSchema', but components from this namespace are not referenceable from schema document 'file:////mySchema.xsd'. If this is the incorrect namespace, perhaps the prefix of 'timing_type' needs to be changed. If this is the correct namespace, then an appropriate 'import' tag should be added to 'file:////mySchema.xsd'.

Any ideas what I'm doing wrong here? How do I just define a whole bunch of children for <machine> that are all simple, have no children, and only have attributes? Thanks in advance!


Solution

  • Since you seem to be learning XSD, it may be easier to build more complete XML samples, and then use some tool to generate an XSD from all those sample XMLs. From that generated XSD you can learn a lot, and it should make it easier for you to change it incrementally to better fit your goals.

    The error is that you cannot have a named type nested under anything other than an xs:schema or an xs:redefine.

    So your snippet would be correct as per below:

    <?xml version="1.0" encoding="utf-8" ?>
    <!--XML Schema generated by QTAssistant/XML Schema Refactoring (XSR) Module (http://www.paschidev.com)-->
    <xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
        <xs:element name="machine">
            <xs:complexType>
                <xs:all>
                    <!-- Definition for the <timing> child element. -->
                    <xs:element name="timing" type="timing_type"/>
                    <!-- Definitions for the other <machine> child elements... -->
                </xs:all>
            </xs:complexType>
        </xs:element>
        <xs:complexType name="timing_type">
            <xs:attribute name="offset" type="xs:string"/>
            <xs:attribute name="period" type="xs:string"/>
        </xs:complexType>
    </xs:schema>
    

    A problem you might run into is related to the use of xs:all instead of xs:sequence or xs:choice. in XSD 1.0, xs:all is very picky in that you can't have more than one occurrence for the timing element.

    The XSD below was generated by a tool. It uses a sequence compositor (instead of all) which would allow for the variation I've added (maxOccurs="unbounded")

    <?xml version="1.0" encoding="utf-8"?>
    <!--XML Schema generated by QTAssistant/XML Schema Refactoring (XSR) Module (http://www.paschidev.com)-->
    <xsd:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <xsd:element name="machine">
        <xsd:complexType>
          <xsd:sequence>
            <xsd:element name="timing" maxOccurs="unbounded">
              <xsd:complexType>
                <xsd:attribute name="offset" type="xsd:string" use="required" />
                <xsd:attribute name="period" type="xsd:string" use="required" />
              </xsd:complexType>
            </xsd:element>
          </xsd:sequence>
        </xsd:complexType>
      </xsd:element>
    </xsd:schema>
    

    If you add to the mix another type of element (as you suggested) and you wish to allow for any number of such element, individually occurring more than once and in any order, then the model below would work. The thing to note here is xsd:choice maxOccurs="unbounded"

    <?xml version="1.0" encoding="utf-8"?>
    <!--XML Schema generated by QTAssistant/XML Schema Refactoring (XSR) Module (http://www.paschidev.com)-->
    <xsd:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <xsd:element name="machine">
        <xsd:complexType>
          <xsd:choice maxOccurs="unbounded">
            <xsd:element name="timing">
              <xsd:complexType>
                <xsd:attribute name="offset" type="xsd:string" use="required" />
                <xsd:attribute name="period" type="xsd:string" use="required" />
              </xsd:complexType>
            </xsd:element>
            <xsd:element name="cycle">
              <xsd:complexType>
                <xsd:attribute name="duration" type="xsd:positiveInteger" use="required" />
                <xsd:attribute name="period" type="xsd:positiveInteger" use="required" />
              </xsd:complexType>
            </xsd:element>          
          </xsd:choice>
        </xsd:complexType>
      </xsd:element>
    </xsd:schema>