Если вы можете перечислить категории и их породы, самый простой способ сделать это проверяемым — использовать имена категорий (и, возможно, также пород) как имена элементов, а не как значения атрибутов.
Если вы сделаете это только для категорий, но не для пород, ваш 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