在XSD中,如何通过属性值限制枚举?

时间:2015-02-13 16:29:41

标签: xml xsd xsd-1.1

在下面的示例xml / xsd中,当用户输入AnimalCategories的值时,我希望AnimalBreeds中的枚举仅允许适当的值。例如,如果用户输入Cat,那么AnimalBreeds的有效选项应该只是Siamese和Persian。我已经查看了关于xsd 1.1中可用的断言和替代方案的帖子,但我无法看到如何将其应用于我的特定需求。

非常感谢任何想法。

Validation

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

2 个答案:

答案 0 :(得分:4)

如果您可以枚举类别及其品种,那么使此类可检查的最简单方法是使用类别名称(以及可选的品种)作为元素名称,而不是属性值。

如果您只针对类别而非品种执行此操作,则您的XML可能采用以下格式:

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

Dog和Cat的元素可以替代AnimalData(您可能希望将其作为摘要,除非您期望某些非狗,非cat实例;您当前的架构表示您不期望任何此类),以及它们的类型源自AnimalData。对于狗,必要的机械看起来像这样:

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

Cat以同样的方式工作。当然,由于属性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的特定于类别的子类型(在下面的示例中,这些是DogCat);为了限制品种,您还需要特定类别的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>

请注意,所有这四种变体都编码有关类别和品种之间相关性的相同信息,但在某些情况下,其他软件比其他软件更容易获取这些信息。

答案 1 :(得分:1)

如果您想使用其他类型,可以在下面找到另一个架构示例。

<?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>
相关问题