Как в XSD ограничить перечисление по значению атрибута?

В приведенном ниже примере xml/xsd, когда пользователь вводит значение для AnimalCategories, я хочу, чтобы перечисление в AnimalBreeds допускало только соответствующие значения. Например, если пользователь вводит «Кошка», то допустимыми вариантами для «AnimalBreeds» должны быть только сиамские и персидские. Я просмотрел сообщения об утверждении и альтернативах, доступных в xsd 1.1, но я не вижу, как применить его к моей конкретной потребности.

Любые идеи очень приветствуются.

Проверка

<?xml version="1.0" encoding="UTF-8"?>
<AnimalsData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="AnimalsData.xsd">
    <AnimalData AnimalCategories="Dog" AnimalBreeds="Boxer"/>
    <AnimalData AnimalCategories="Cat" AnimalBreeds="Siamese"/>
</AnimalsData>


<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" elementFormDefault="qualified" attributeFormDefault="unqualified" vc:minVersion="1.1">
    <xs:complexType name="AnimalsDataType">
        <xs:sequence>
            <xs:element ref="AnimalData" maxOccurs="unbounded"/>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="AnimalDataType">
        <xs:attribute ref="AnimalCategories" use="required"/>
        <xs:attribute ref="AnimalBreeds" use="required"/>
    </xs:complexType>
    <xs:simpleType name="AnimalCategoriesType">
        <xs:restriction base="xs:string">
            <xs:enumeration value="Dog"/>
            <xs:enumeration value="Cat"/>
        </xs:restriction>
    </xs:simpleType>
    <xs:simpleType name="AnimalBreedsType">
        <xs:restriction base="xs:string">
            <xs:enumeration value="Boxer"/>
            <xs:enumeration value="Rottweiler"/>
            <xs:enumeration value="Siamese"/>
            <xs:enumeration value="Persian"/>
        </xs:restriction>
    </xs:simpleType>
    <xs:element name="AnimalsData" type="AnimalsDataType"/>
    <xs:element name="AnimalData" type="AnimalDataType"/>
    <xs:attribute name="AnimalCategories" type="AnimalCategoriesType"/>
    <xs:attribute name="AnimalBreeds" type="AnimalBreedsType"/>
</xs:schema>

person Bama91    schedule 13.02.2015    source источник
comment
Вы понимаете, что выражение вашего ограничения в XSD само по себе ничего не гарантирует в отношении того, когда пользователь выбирает значение или показывает только соответствующие значения, верно?   -  person kjhughes    schedule 13.02.2015
comment
Конечно... Я соответственно обновил свой пост. Я просто имел в виду автоматическое завершение при проверке связанной схемы в редакторе, таком как XMLSply. См. прикрепленное изображение.   -  person Bama91    schedule 13.02.2015


Ответы (2)


Если вы можете перечислить категории и их породы, самый простой способ сделать это проверяемым — использовать имена категорий (и, возможно, также пород) как имена элементов, а не как значения атрибутов.

Если вы сделаете это только для категорий, но не для пород, ваш XML может иметь следующий вид:

<AnimalsData>
  <Dog Breeds="Boxer"/>
  <Cat Breeds="Siamese"/>
</AnimalsData>

Элементы Dog и Cat сделаны заменяемыми для AnimalData (которые вы можете сделать абстрактными, если только вы не ожидаете каких-либо экземпляров, отличных от собак и кошек; ваша текущая схема говорит, что вы не ожидаете ничего подобного), а их типы получены из что у AnimalData. Для Dog необходимая техника выглядит так:

<xs:complexType name="Dog">
  <xs:complexContent>
    <xs:restriction base="AnimalDataType">
      <xs:attribute name="AnimalBreeds" 
        use="required" 
        type="DogBreedsType"/>
    </xs:restriction>
  </xs:complexContent>
</xs:complexType>

<xs:simpleType name="DogBreedsType">
  <xs:restriction base="AnimalBreedsType">
    <xs:enumeration value="Boxer"/>
    <xs:enumeration value="Rottweiler"/>
  </xs:restriction>
</xs:simpleType>

<xs:element name="Dog" type="Dog" substitutionGroup="AnimalData"/>

Кошка работает так же. И, конечно же, поскольку атрибут AnimalCategories теперь избыточен по отношению к имени типа элемента, мы его убрали:

<xs:complexType name="AnimalDataType">
  <xs:attribute name="AnimalBreeds" use="required"
                type="AnimalBreedsType"/>
</xs:complexType>

Более тщательное переосмысление также перемещает породы со значений атрибутов на имена элементов. XML будет выглядеть так:

<AnimalsData>
  <Dog><Boxer/></Dog>
  <Cat><Siamese/></Cat>
</AnimalsData>

Схема будет выглядеть примерно так:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
           xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" 
           elementFormDefault="qualified" 
           attributeFormDefault="unqualified" 
           vc:minVersion="1.1">
  <xs:complexType name="AnimalsDataType">
    <xs:sequence>
      <xs:element ref="AnimalData" maxOccurs="unbounded"/>
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="AnimalDataType">
    <xs:sequence>
      <xs:element ref="Breed"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="Dog">
    <xs:complexContent>
      <xs:restriction base="AnimalDataType">
        <xs:sequence>
          <xs:element ref="CanineBreed"/>
        </xs:sequence>
      </xs:restriction>
    </xs:complexContent>
  </xs:complexType>
  <xs:complexType name="Cat">
    <xs:complexContent>
      <xs:restriction base="AnimalDataType">
        <xs:sequence>
          <xs:element ref="FelineBreed"/>
        </xs:sequence>
      </xs:restriction>
    </xs:complexContent>
  </xs:complexType>

  <xs:element name="AnimalsData" type="AnimalsDataType"/>
  <xs:element name="AnimalData" type="AnimalDataType" abstract="true"/>
  <xs:element name="Dog" type="Dog" substitutionGroup="AnimalData"/>
  <xs:element name="Cat" type="Cat" substitutionGroup="AnimalData"/>

  <xs:element name="Breed" abstract="true">
    <xs:complexType><xs:sequence/></xs:complexType>
  </xs:element>
  <xs:element name="CanineBreed" abstract="true" 
              substitutionGroup="Breed"/>
  <xs:element name="FelineBreed" abstract="true" 
              substitutionGroup="Breed"/>
  <xs:element name="Boxer" substitutionGroup="CanineBreed"/>
  <xs:element name="Rottweiler" substitutionGroup="CanineBreed"/>
  <xs:element name="Siamese" substitutionGroup="FelineBreed"/>
  <xs:element name="Persian" substitutionGroup="FelineBreed"/>

</xs:schema>

Чтобы использовать условные типы, определите подтипы AnimalDataType для конкретных категорий (в приведенном ниже примере это Dog и Cat); чтобы ограничить породы, вам также потребуются подтипы AnimalBreedsType для конкретных категорий. Затем используйте xs:alternative в объявлении элемента для AnimalData, чтобы присвоить элементу правильный ограниченный тип. Схема в целом выглядит так. (Я сделал два атрибута локальными для AnimalData, потому что меня смущает, что они глобальные.)

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
           xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" 
           elementFormDefault="qualified" 
           attributeFormDefault="unqualified" 
           vc:minVersion="1.1">
  <xs:complexType name="AnimalsDataType">
    <xs:sequence>
      <xs:element ref="AnimalData" maxOccurs="unbounded"/>
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="AnimalDataType">
    <xs:attribute ref="AnimalCategories" use="required"/>
    <xs:attribute ref="AnimalBreeds" use="required"/>
  </xs:complexType>
  <xs:simpleType name="AnimalCategoriesType">
    <xs:restriction base="xs:string">
      <xs:enumeration value="Dog"/>
      <xs:enumeration value="Cat"/>
    </xs:restriction>
  </xs:simpleType>
  <xs:simpleType name="AnimalBreedsType">
    <xs:restriction base="xs:string">
      <xs:enumeration value="Boxer"/>
      <xs:enumeration value="Rottweiler"/>
      <xs:enumeration value="Siamese"/>
      <xs:enumeration value="Persian"/>
    </xs:restriction>
  </xs:simpleType>
  <xs:element name="AnimalsData" type="AnimalsDataType"/>
  <xs:element name="AnimalData" type="AnimalDataType"/>
  <xs:attribute name="AnimalCategories" type="AnimalCategoriesType"/>
  <xs:attribute name="AnimalBreeds" type="AnimalBreedsType"/>
</xs:schema>

Чтобы использовать утверждения, достаточно добавить следующие утверждения в объявление для AnimalDataType:

<xs:complexType name="AnimalDataType">
  <xs:attribute ref="AnimalCategories" use="required"/>
  <xs:attribute ref="AnimalBreeds" use="required"/>

  <xs:assert test="if (@AnimalCategories='Dog')
    then @AnimalBreeds = ('Boxer', 'Rottweiler')
    else true()"/>
  <xs:assert test="if (@AnimalCategories='Cat')
      then @AnimalBreeds = ('Siamese', 'Persian')
      else true()"/>
</xs:complexType>

Обратите внимание, что все четыре из этих вариантов кодируют одну и ту же информацию о корреляции между категорией и породой, но в некоторых случаях эта информация более доступна для другого программного обеспечения, чем в других.

person C. M. Sperberg-McQueen    schedule 13.02.2015

Если вы хотите использовать альтернативные типы, вы можете найти ниже другой пример вашей схемы.

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" elementFormDefault="qualified"
    attributeFormDefault="unqualified" vc:minVersion="1.1">
    <xs:complexType name="AnimalsDataType">
        <xs:sequence>
            <xs:element ref="AnimalData" maxOccurs="unbounded"/>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="AnimalDataType">
        <xs:attribute ref="AnimalCategories" use="required"/>
    </xs:complexType>
    <xs:complexType name="DogDataType">
        <xs:complexContent>
            <xs:extension base="AnimalDataType">
                <xs:attribute name="AnimalBreeds" type="DogBreedsType" use="required"/>
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>
    <xs:complexType name="CatDataType">
        <xs:complexContent>
            <xs:extension base="AnimalDataType">
                <xs:attribute name="AnimalBreeds" type="CatBreedsType" use="required"/>
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>
    <xs:simpleType name="AnimalCategoriesType">
        <xs:restriction base="xs:string">
            <xs:enumeration value="Dog"/>
            <xs:enumeration value="Cat"/>
        </xs:restriction>
    </xs:simpleType>
    <xs:simpleType name="DogBreedsType">
        <xs:restriction base="xs:string">
            <xs:enumeration value="Boxer"/>
            <xs:enumeration value="Rottweiler"/>
        </xs:restriction>
    </xs:simpleType>

    <xs:simpleType name="CatBreedsType">
        <xs:restriction base="xs:string">
            <xs:enumeration value="Siamese"/>
            <xs:enumeration value="Persian"/>
        </xs:restriction>
    </xs:simpleType>

    <xs:element name="AnimalsData" type="AnimalsDataType"/>
    <xs:element name="AnimalData" type="AnimalDataType">
        <xs:alternative test="@AnimalCategories='Dog'" type="DogDataType"/>
        <xs:alternative test="@AnimalCategories='Cat'" type="CatDataType"/>
    </xs:element>

    <xs:attribute name="AnimalCategories" type="AnimalCategoriesType"/>
</xs:schema>
person Octavian    schedule 15.02.2015