2

在下面的示例 xml/xsd 中,当用户输入 AnimalCategories 的值时,我希望 AnimalBreeds 中的枚举只允许适当的值。例如,如果用户输入 Cat,那么 AnimalBreeds 的有效选择应该只有 Siamese 和 Persian。我已经查看了有关 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>
4

2 回答 2

4

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

如果您只为类别而不是品种执行此操作,则您的 XML 可能采用如下形式:

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

元素 Dog 和 Cat 可替代 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(在下面的示例中,它们是Dogand Cat);要限制品种,您还需要特定类别的AnimalBreedsType. 然后xs:alternative在元素声明中使用 forAnimalData为元素分配正确的受限类型。整个架构看起来像这样。(我将这两个属性设置为本地属性,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>

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

于 2015-02-13T18:19:57.453 回答
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>
于 2015-02-15T23:03:43.317 回答