Search code examples
xmlxsdxsd-validation

Using XSD to validate multiple roots


I'm working on this project where we are only allowed to use one XSD file to validate multiple XML files.

I have this one problem I can't seem to figure out nor can I find something similar that was asked before, my apologies if this is a duplicate question.

Say I have this one XML document call it currencies.xml that has the following XML inside it:

<index>
    <currency>USD</currency>
    <currency>EURO</currency>
</index>

which must contain at least 1 <currency\> element but can have as many as need be. Now, say I have multiple other XML file's with the same name as the currency values inside currencies.xml, but for simplicity sake lets take only the USD currency's file USD.xml which contains the following:

<index>currency="USD">
    <country short="USA">United States of America</country>
</index>    

This time its permissible to have 0 <country\> elements, and also as many as need be.

So inside my validation XSD file I have the following:

<xs:complexType name="root">
    <xs:choice>
        <xs:element name="currency" type="WithoutAttrib"/>
        <xs:element name="country" type="WithAttrib"/>
    </xs:choice>
    <xs:attribute name="currency" type="rootAttribute" />
</xs:complexType>

<xs:complexType name="WithAttrib">
    <xs:complexContent>
        <xs:extension base="root">
            <xs:sequence minOccurs="0" maxOccurs="unbounded">
                <xs:element name="country" minOccurs="0" maxOccurs="unbounded">
                    <xs:complexType>
                        <xs:simpleContent>
                            <xs:extension base="stringElement">
                                <xs:attribute name="short" use="required"/>
                            </xs:extension>
                        </xs:simpleContent>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:extension>
    </xs:complexContent>
</xs:complexType>

<xs:complexType name="WithoutAttrib">
    <xs:complexContent>
        <xs:extension base="root">
            <xs:sequence minOccurs="1" maxOccurs="unbounded">
                <xs:element name="currency">
                    <xs:simpleType>
                        <xs:restriction base="xs:string">
                            <xs:maxLength value="30"></xs:maxLength>
                        </xs:restriction>
                    </xs:simpleType>
                </xs:element>
            </xs:sequence>
        </xs:extension>
    </xs:complexContent>
</xs:complexType>

<xs:element name="index" type="root"/>

The stringElement is defined as follows:

<xs:simpleType name="stringElement">
    <xs:restriction base="xs:string"/>
</xs:simpleType>

So far this was the best solution I could come up with but it doesn't work as I need it to, could someone perhaps help me out by either providing a link to a similar question that I can use or perhaps give me some advice on how to get this working.

I'm also not entirely sure if the attribute should be declared inside the root, any advice regarding it would be appreciated as well.

In case you need more information about something specific, leave me a comment and I'll make an edit. Thanks in advance!


Solution

  • You have nothing in the XML to differentiate between the schema rules you require, so your XSD must be a superset of all the valid attributes and elements in <index>. Is the XML format fixed or can you change it?

    The following does what you want, but as you have attributes in the index element, the choice can not group the attribute with the country element.

    Its less than ideal.

    enter image description here

      <?xml version="1.0" encoding="utf-8" ?>
      <!--Created with Liquid Studio 2021 (https://www.liquid-technologies.com)-->
      <xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
         <xs:element name="index">
            <xs:complexType>
               <xs:choice>
                  <xs:element name="currency" type="currencyType" maxOccurs="unbounded" />
                  <xs:element name="country">
                     <xs:complexType>
                        <xs:simpleContent>
                           <xs:extension base="xs:string">
                              <xs:attribute name="short" type="currencyType" />
                           </xs:extension>
                        </xs:simpleContent>
                     </xs:complexType>
                  </xs:element>
               </xs:choice>
               <xs:attribute name="currency" type="currencyType" />
            </xs:complexType>
         </xs:element>
         <xs:simpleType name="currencyType">
            <xs:restriction base="xs:string">
               <xs:enumeration value="USD" />
               <xs:enumeration value="GBP" />
               <xs:enumeration value="EUR" />
            </xs:restriction>
         </xs:simpleType>
      </xs:schema>