Question

I have a XML Schema which describes a XML instance where the <item> element contains other elements such as:

  • tariffs
  • category
  • director
  • tag
  • country
  • year
  • genre

These elements may appear in an arbitrary sequence. I must indicate in my XSD that they may appear in a random order.

I read that one would need to use <xs:all> but I wasn't able to make it work.

This is my XML instance:

<videos>
    <item id="17314" description="Жизнь харизматичного ... жемчужины" age-limit="12">
        <tariffs>
            <tariff id="2" type-id="1" type-alias="subscription" price="179" duration="30"/>
            <tariff id="6" type-id="2" type-alias="purchase" price="79" duration="30"/>
        </tariffs>
        <category id="71" title="Фильмы"/>
        <director id="27449" title="Гор Вербински"/>
        <tag id="752" title="пираты"/>
        <tag id="894" title="любовь"/>
        <tag id="1164" title="флот"/>
        <tag id="1789" title="море"/>
        <tag id="1790" title="сокровища"/>
        <tag id="1811" title="нечисть"/>
        <tag id="2292" title="похищение"/>
        <tag id="2608" title="остров"/>
        <tag id="2646" title="капитан"/>
        <tag id="2999" title="проклятие"/>
        <tag id="5944" title="магия"/>
        <tag id="9888" title="18 век"/>
        <tag id="13539" title="тайна"/>
        <tag id="16045" title="спасение"/>
        <tag id="18576" title="12+"/>
        <country id="515" title="США"/>
        <year id="227" title="2003"/>
        <genre id="674" title="художественное"/>
        <genre id="690" title="боевик"/>
        <genre id="702" title="приключения"/>
        <genre id="5938" title="фэнтези"/>
        <genre id="6467" title="фестивальное"/>
        <genre id="8964" title="HD фильмы"/>
    </item>
    <item id="15922" description="Супермодель ... один шаг." duration="89" url="http://www.tvzavr.ru/Svadba-po-obmenu" type="Single" rates="2" rating="6" ratesum="11" views="39331" topic="20584" seo-alias="Svadba-po-obmenu" requires_subscription="No" geo-limit="RU" name="Свадьба по обмену" age-limit="16">
        <category id="71" title="Фильмы"/>
        <director id="2264" title="Дмитрий Грачев"/>
        <tag id="894" title="любовь"/>
        <tag id="2384" title="месть"/>
        <tag id="2425" title="телевидение"/>
        <tag id="6156" title="Россия"/>
        <tag id="9582" title="современность"/>
        <tag id="9598" title="16+"/>
        <tag id="13556" title="супруги"/>
        <tag id="15526" title="обман"/>
        <tag id="15984" title="ссора"/>
        <country id="122" title="Россия"/>
        <year id="234" title="2010"/>
        <genre id="674" title="художественное"/>
        <genre id="697" title="комедия"/>
        <genre id="698" title="мелодрама"/>
    </item>
    <item id="16274" description="Жил-был ... арабской сказке." duration="95" url="http://www.tvzavr.ru/Iznougud-ili-Kalif-na-chas" type="Single" rates="2" rating="6" ratesum="11" views="14751" topic="21192" seo-alias="Iznougud-ili-Kalif-na-chas" requires_subscription="No" geo-limit="KZ BY RU" name="Изноугуд или Калиф на час" age-limit="12">
        <category id="71" title="Фильмы"/>
        <director id="25913" title="Патрик Брауде"/>
        <tag id="894" title="любовь"/>
        <tag id="2323" title="средневековье"/>
        <tag id="2716" title="волшебство"/>
        <tag id="9890" title="Восток"/>
        <tag id="13617" title="рабство"/>
        <tag id="15985" title="прислуга"/>
        <tag id="18576" title="12+"/>
        <country id="2543" title="Франция"/>
        <year id="229" title="2005"/>
        <genre id="674" title="художественное"/>
        <genre id="697" title="комедия"/>
    </item>
    <item id="9660" description="Забавные ... развлечения!" duration="546" url="http://www.tvzavr.ru/Oazis-Oskara" type="Set" rates="90" rating="5" ratesum="412" views="2898560" topic="12826" seo-alias="Oazis-Oskara" requires_subscription="No" geo-limit="RU UA BY KZ AZ AM KG UZ TM TJ MD IN KR US PL DE" name="Оазис Оскара" age-limit="0">
        <category id="678" title="Мультфильмы"/>
        <director id="16910" title="Тае Сик Шин"/>
        <director id="16911" title="Фредерик Мартин"/>
        <director id="16912" title="Сильвейн Бойдо"/>
        <tag id="2774" title="собака"/>
        <tag id="5128" title="пустыня"/>
        <tag id="7104" title="друзья"/>
        <tag id="9558" title="зверушки"/>
        <tag id="13586" title="волки"/>
        <tag id="13606" title="погоня"/>
        <tag id="15473" title="испытание"/>
        <tag id="15706" title="птицы"/>
        <tag id="15988" title="еда"/>
        <country id="2543" title="Франция"/>
        <year id="10996" title="2011"/>
        <genre id="694" title="детское/семейное"/>
        <genre id="702" title="приключения"/>
        <genre id="9572" title="для дошкольников"/>
        <genre id="9573" title="для школьников"/>
    </item>
    <item id="10366" description="Милый ... фильмов." duration="468" url="http://www.tvzavr.ru/Bernard" type="Set" rates="87" rating="5" ratesum="416" views="3885650" topic="13610" seo-alias="Bernard" requires_subscription="No" geo-limit="RU UA BY KZ AZ AM KG UZ TM TJ MD IN KR US PL DE" name="Бернард" age-limit="0">
        <category id="678" title="Мультфильмы"/>
        <director id="17936" title="Хосе Луис Уча"/>
        <tag id="72" title="автомобили"/>
        <tag id="98" title="футбол"/>
        <tag id="1789" title="море"/>
        <tag id="6338" title="неудачник"/>
        <tag id="7104" title="друзья"/>
        <tag id="9558" title="зверушки"/>
        <tag id="10407" title="спортсмены"/>
        <tag id="13606" title="погоня"/>
        <tag id="15246" title="соперничество"/>
        <tag id="15289" title="труд"/>
        <tag id="15706" title="птицы"/>
        <tag id="15988" title="еда"/>
        <tag id="16028" title="опасность"/>
        <country id="2543" title="Франция"/>
        <country id="2600" title="Испания"/>
        <country id="8789" title="Южная Корея"/>
        <year id="228" title="2004"/>
        <genre id="694" title="детское/семейное"/>
        <genre id="702" title="приключения"/>
        <genre id="9572" title="для дошкольников"/>
        <genre id="9573" title="для школьников"/>
    </item>
</videos>

And this is a XSD which validates the file above but does not attend my needs, since it enforces the ordering of the elements.

<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="videos">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="item" maxOccurs="unbounded" minOccurs="1">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="tariffs" minOccurs="0">
                <xs:complexType>
                  <xs:sequence>
                    <xs:element name="tariff" maxOccurs="unbounded" minOccurs="0">
                      <xs:complexType>
                        <xs:simpleContent>
                          <xs:extension base="xs:string">
                            <xs:attribute type="xs:int" name="id" use="required"/>
                            <xs:attribute type="xs:int" name="type-id" use="required"/>
                            <xs:attribute type="xs:string" name="type-alias" use="required"/>
                            <xs:attribute type="xs:short" name="price" use="required"/>
                            <xs:attribute type="xs:int" name="duration" use="required"/>
                          </xs:extension>
                        </xs:simpleContent>
                      </xs:complexType>
                    </xs:element>
                  </xs:sequence>
                </xs:complexType>
              </xs:element>
              <xs:element name="category" maxOccurs="unbounded" minOccurs="0">
                <xs:complexType>
                  <xs:simpleContent>
                    <xs:extension base="xs:string">
                      <xs:attribute type="xs:short" name="id" use="optional"/>
                      <xs:attribute type="xs:string" name="title" use="optional"/>
                    </xs:extension>
                  </xs:simpleContent>
                </xs:complexType>
              </xs:element>
              <xs:element name="director" maxOccurs="unbounded" minOccurs="0">
                <xs:complexType>
                  <xs:simpleContent>
                    <xs:extension base="xs:string">
                      <xs:attribute type="xs:short" name="id" use="optional"/>
                      <xs:attribute type="xs:string" name="title" use="optional"/>
                    </xs:extension>
                  </xs:simpleContent>
                </xs:complexType>
              </xs:element>
              <xs:element name="tag" maxOccurs="unbounded" minOccurs="0">
                <xs:complexType>
                  <xs:simpleContent>
                    <xs:extension base="xs:string">
                      <xs:attribute type="xs:short" name="id" use="optional"/>
                      <xs:attribute type="xs:string" name="title" use="optional"/>
                    </xs:extension>
                  </xs:simpleContent>
                </xs:complexType>
              </xs:element>
              <xs:element name="country" maxOccurs="unbounded" minOccurs="0">
                <xs:complexType>
                  <xs:simpleContent>
                    <xs:extension base="xs:string">
                      <xs:attribute type="xs:short" name="id" use="optional"/>
                      <xs:attribute type="xs:string" name="title" use="optional"/>
                    </xs:extension>
                  </xs:simpleContent>
                </xs:complexType>
              </xs:element>
              <xs:element name="year" maxOccurs="1" minOccurs="0">
                <xs:complexType>
                  <xs:simpleContent>
                    <xs:extension base="xs:string">
                      <xs:attribute type="xs:short" name="id" use="optional"/>
                      <xs:attribute type="xs:short" name="title" use="optional"/>
                    </xs:extension>
                  </xs:simpleContent>
                </xs:complexType>
              </xs:element>
              <xs:element name="genre" maxOccurs="unbounded" minOccurs="0">
                <xs:complexType>
                  <xs:simpleContent>
                    <xs:extension base="xs:string">
                      <xs:attribute type="xs:short" name="id" use="optional"/>
                      <xs:attribute type="xs:string" name="title" use="optional"/>
                    </xs:extension>
                  </xs:simpleContent>
                </xs:complexType>
              </xs:element>
            </xs:sequence>
            <xs:attribute type="xs:short" name="id" use="optional"/>
            <xs:attribute type="xs:string" name="name" use="optional"/>
            <xs:attribute type="xs:string" name="type" use="optional"/>
            <xs:attribute type="xs:string" name="requires_subscription" use="optional"/>
            <xs:attribute type="xs:byte" name="age-limit" use="optional"/>
            <xs:attribute type="xs:string" name="geo-limit" use="optional"/>
            <xs:attribute type="xs:string" name="url" use="optional"/>
            <xs:attribute type="xs:string" name="description" use="optional"/>
            <xs:attribute type="xs:int" name="views" use="optional"/>
            <xs:attribute type="xs:int" name="topic" use="optional"/>
            <xs:attribute type="xs:string" name="seo-alias" use="optional"/>
            <xs:attribute type="xs:string" name="requires-subscription" use="optional"/>
            <xs:attribute type="xs:int" name="rating" use="optional"/>
            <xs:attribute type="xs:short" name="rates" use="optional"/>
            <xs:attribute type="xs:short" name="ratesum" use="optional"/>
            <xs:attribute type="xs:string" name="duration" use="optional"/>
            <xs:attribute type="xs:string" name="season-name" use="optional"/>
            <xs:attribute type="xs:int" name="season-number" use="optional"/>
            <xs:attribute type="xs:string" name="set-name" use="optional"/>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>

How can I change it so it will validate when the child elements inside <item> appear in any order?

Was it helpful?

Solution

You can't use xs:all in XSD 1.0 because although it allows elements in any order, it only allows one or zero of each.

But the schema you provided does not require any child elements to be present, which means that an item like this:

<item></item>

would still be valid (since all the attributes are also declared as optional). Is that the case?

If so, you don't need <xs:all> and can replace the <xs:sequence> inside the <xs:element name="item"> declaration for an optional and unbounded <xs:choice>:

<xs:element name="item" maxOccurs="unbounded" minOccurs="1">
    <xs:complexType>
        <xs:choice minOccurs="0" maxOccurs="unbounded">
        ...
        </xs:choice>
        <xs:attribute type="xs:short" name="id" use="optional"/>
        ...
    </xs:complexType>
</xs:element>

This will validate empty <item> elements, <item> elements containing child elements in any order, any quantity (including zero). It will validate this:

<item>
    <tag id="752" title="пираты"/>
    <tag id="894" title="любовь"/>
    <category id="71" title="Фильмы"/>
    <tag id="1164" title="флот"/>
    <country id="515" title="США"/>
    <tag id="1789" title="море"/>
    <director id="27449" title="Гор Вербински"/>
    <tag id="1790" title="сокровища"/>
    <tag id="1811" title="нечисть"/>
    <genre id="702" title="приключения"/>
    <tag id="2292" title="похищение"/>
    <year id="227" title="2003"/>
    <genre id="674" title="художественное"/>
    <genre id="690" title="боевик"/>
    <tariffs>
        <tariff id="2" type-id="1" type-alias="subscription" price="179" duration="30"/>
        <tariff id="6" type-id="2" type-alias="purchase" price="79" duration="30"/>
    </tariffs>
    <genre id="5938" title="фэнтези"/>
</item>

And this:

<item>
    <tag id="1789" title="море"/>
    <director id="27449" title="Гор Вербински"/>
    <tag id="1790" title="сокровища"/>
    <tag id="1811" title="нечисть"/>
</item>

This may not be the best design, however. Do you really want to allow empty <item>s or <item>s containing only tags and director? If not, you might consider an alternative design or using XSD 1.1.

An alternative design

If you are designing this schema, a better solution would be to change the design and accommodate the repeating elements in wrapper elements. It's a better design because it represents the elements as a group, or array, which is what they actually are. It makes it easier to process them, use them in language-mapping software, etc.

If you can change the design, an alternative design could be a schema which would allow something like this:

<item id="17314" ... >
    <tariffs>
        <tariff .../>
        <tariff .../>
    </tariffs>
    <categories>
        <category id="71" title="Фильмы"/>
        <category id="72" title="театрь"/>
    </categories>
    <directors>
        <director id="16910" title="Константин Станиславский"/>
        <director id="16911" title="Вуди Аллен"/>
        <director id="16912" title="Педро Альмодовар"/>
    </directors>
    <tags>
        <tag id="752" title="деньги"/>
        <tag id="894" title="любовь"/>
        <tag id="1164" title="вещь"/>
    </tags>
    <countries>
        <country id="2543" title="Франция"/>
        <country id="2600" title="Испания"/>
        <country id="8789" title="Россия"/>
    </countries>
    <year id="227" title="2003"/>
    <genres>
        <genre id="674" title="художественное"/>
        <genre id="690" title="боевик"/>
        <genre id="702" title="приключения"/>
        <genre id="5938" title="фэнтези"/>
        <genre id="6467" title="фестивальное"/>
        <genre id="8964" title="HD фильмы"/>
    </genres>
</item>

Where you could use xs:all to allow each collection to occur at most once in <item>, in any order (allowing for optional collections, such as tariff):

<xs:element name="item">
   <xs:complexType>
      <xs:all>
          <xs:element ref="tariffs" minOccurs="0"/>
          <xs:element ref="categories"/>
          <xs:element ref="directors"/>
          <xs:element ref="tags"/>
          <xs:element ref="countries"/>
          <xs:element ref="year"/>
          <xs:element ref="genres"/>
      </xs:all>
      <xs:attribute type="xs:short"  name="id" use="optional"/>
      ...
   </xs:complexType>
</xs:element>

XSD 1.1

You can't have xs:all with unbounded elements in XSD 1.0. As I showed in the beginning of this answer, your solution doesn't need it since all elements in <item> are optional. But if you actually need to require elements in <item>, can't change your design and still want to allow elements in any order, you can validate your code using the same schema you provided, as long as you use it with XSD 1.1.

To do that you will need to use a parser that supports XSD 1.1 and to add two attributes to your <xs:schema> root element, as shown below:

<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" vc:minVersion="1.1"> 
    ...

Then you can replace the <xs:sequence> in the declaration for the <item> element in your XSD for <xs:all> and it will work when validated in a parser that supports XSD 1.1.

OTHER TIPS

The way I found to achiev this is to use xs:choice (unbounded) inside xs:sequence, e.g.

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="unqualified">

    <xs:element name="item">
        <xs:complexType>
            <xs:sequence>
                <xs:choice maxOccurs="unbounded">
                    <xs:element maxOccurs="1" minOccurs="0" name="tariffs">
                        <xs:complexType>
                            <xs:sequence>
                                <xs:element name="tariff">
                                    <xs:complexType>
                                        <xs:attribute name="id"/>
                                        <xs:attribute name="type-id"/>
                                        <xs:attribute name="type-alias"/>
                                        <xs:attribute name="price"/>
                                        <xs:attribute name="duration"/>
                                    </xs:complexType>
                                </xs:element>
                            </xs:sequence>
                        </xs:complexType>
                    </xs:element>
                    <xs:element name="category">
                        <xs:complexType>
                            <xs:attributeGroup ref="IdTitle"/>
                        </xs:complexType>
                    </xs:element>
                    <xs:element maxOccurs="unbounded" minOccurs="0" name="director">
                        <xs:complexType>
                            <xs:attributeGroup ref="IdTitle"/>
                        </xs:complexType>
                    </xs:element>
                    <xs:element maxOccurs="unbounded" minOccurs="0" name="tag">
                        <xs:complexType>
                            <xs:attributeGroup ref="IdTitle"/>
                        </xs:complexType>
                    </xs:element>
                    <xs:element name="country">
                        <xs:complexType>
                            <xs:attributeGroup ref="IdTitle"/>
                        </xs:complexType>
                    </xs:element>
                    <xs:element maxOccurs="unbounded" minOccurs="0" name="genre">
                        <xs:complexType>
                            <xs:attributeGroup ref="IdTitle"/>
                        </xs:complexType>
                    </xs:element>
                    <xs:element name="year">
                        <xs:complexType>
                            <xs:attributeGroup ref="IdTitle"/>
                        </xs:complexType>
                    </xs:element>
                </xs:choice>
            </xs:sequence>
            <xs:attribute name="id"/>
            <xs:attribute name="description"/>
            <xs:attribute name="age-limit"/>
            <xs:attribute name="duration"/>
            <xs:attribute name="url"/>
        </xs:complexType>
    </xs:element>
    <xs:attributeGroup name="IdTitle">
        <xs:attribute name="id"/>
        <xs:attribute name="title"/>
    </xs:attributeGroup>
</xs:schema>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top