允许XSD架构中元素的随机顺序

时间:2014-04-30 12:05:22

标签: xml xsd xml-validation

我有一个XML Schema,它描述了一个XML实例,其中<item>元素包含其他元素,例如:

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

这些元素可能以任意顺序出现。我必须在我的XSD中说明它们可能以随机顺序出现。

我读到需要使用<xs:all>,但我无法使其正常工作。

这是我的XML实例:

<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>

这是一个验证上述文件但不符合我需求的XSD,因为它强制执行元素的排序。

<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>

如何更改它以便在<item>内的子元素按任何顺序出现时验证?

1 个答案:

答案 0 :(得分:3)

您无法在XSD 1.0中使用xs:all,因为虽然它允许任何顺序的元素,但它只允许一个

但是您提供的架构不需要存在任何子元素,这意味着item就像这样:

<item></item>

仍然有效(因为所有属性也声明为optional)。是这样的吗?

如果是这样,您不需要<xs:all>并且可以替换<xs:sequence>声明中的<xs:element name="item">以获取可选且无界<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>

这将验证包含任何顺序子元素,任何数量(包括零)的空<item>元素,<item>元素。它将验证这一点:

<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>

而且:

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

然而,这可能不是最好的设计。你真的想让空<item>个或<item>只包含标签和导演吗?如果没有,您可以考虑使用替代设计或使用XSD 1.1。

替代设计

如果您正在设计此架构,更好的解决方案是更改设计并在包装器元素中容纳重复元素。这是一个更好的设计,因为它将元素表示为一个组或数组,这实际上就是它们。它使处理它们变得更容易,在语言映射软件中使用它们等。

如果你可以改变设计,另一种设计可能是一个允许这样的模式:

<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>

您可以使用xs:all允许每个集合在<item>中以任意顺序发布一次(允许可选集合,例如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

在XSD 1.0中,您不能拥有xs:all无限元素。正如我在本答案开头所示,您的解决方案不需要它,因为<item>中的所有元素都是可选的。但是,如果您确实需要<item>中的元素,无法更改您的设计并仍希望允许任何顺序的元素,您可以使用您提供的相同模式验证您的代码,只要您使用它XSD 1.1。

为此,您需要使用支持XSD 1.1的解析器,并向<xs:schema>根元素添加两个属性,如下所示:

<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"> 
    ...

然后,您可以将XSD中<xs:sequence>元素的声明中的<item>替换为<xs:all>,并且在支持XSD 1.1的解析器中进行验证时,它将起作用。