使用XSD 1.1的动态枚举限制

时间:2012-11-30 22:17:09

标签: enums xsd w3c xsd-validation xsd-1.1

我正在尝试使用XSD 1.1创建一个模式定义,其中一个元素的结果依赖于其他元素。例如,我有下拉列表中的国家/地区列表以及每个国家/地区的州列表。当一个人选择一个国家时,只能选择该国家的州。我想要达到的伪代码看起来像这样。

<xs:schema xmlns:ie="http://www.interviewexchange.com" xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="country">       
    <xs:simpleType>
        <xs:restriction base="xs:string">
            <xs:enumeration value="USA" />
            <xs:enumeration value="UK" />
            <xs:enumeration value="India" />
        </xs:restriction>
    </xs:simpleType>
</xs:element>
<xs:element name="state">       
    <xs:simpleType>
        <xs:restriction base="xs:string">
            <assert test="if (country eq 'USA')">
            <xs:enumeration value="MA" />
            <xs:enumeration value="AR" />
            <xs:enumeration value="NY" />
            </assert">
            <assert test="if (country eq 'India')">
            <xs:enumeration value="AP" />
            <xs:enumeration value="TN" />
            <xs:enumeration value="MP" />
            </assert">
        </xs:restriction>
    </xs:simpleType>
</xs:element>

请建议我是否遵循正确的方法,如果我遵循正确的方法,任何人都可以向我提供如何实现这一限制的代码吗?在此先感谢...

1 个答案:

答案 0 :(得分:10)

你越来越近了。

在XSD 1.1中,断言只能向下查看子树,而不是向上或向上,所以如果你想在这里使用断言,你会想要把它们放在'state'的类型中但是在''的类型中地址:

<xs:element name="address">
  <xs:complexType>
    <xs:sequence>
      <xs:element ref="street"/>
      <xs:element ref="city"/>
      <xs:element ref="state" minOccurs="0"/>
      <xs:element ref="country"/>
    </xs:sequence>
    <xs:assert test="(country = 'UK' and not(state))
      or
      (country = 'US' and state = ('MA', 'AR', 'NY'))
      or
      (country = 'IN' and state = ('AP', 'TN', 'MP'))
      "/>
  </xs:complexType>
</xs:element>

另一种方法(也在XSD 1.1中)是使用条件类型赋值。这允许基于XPath表达式为元素分配不同的类型,XPath表达式可以引用其元素(但不能引用其子元素)。如果我们将country和state移动到属性(然后,为了保持一致性,将street和city移动到属性),我们可以使用条件类型赋值。首先,定义我们想要的各种简单类型:

<xs:simpleType name="US-states">
  <xs:restriction base="xs:NMTOKEN">
    <xs:enumeration value="MA" />
    <xs:enumeration value="AR" />
    <xs:enumeration value="NY" />      
  </xs:restriction>
</xs:simpleType>

<xs:simpleType name="IN-states">
  <xs:restriction base="xs:NMTOKEN">
    <xs:enumeration value="AP" />
    <xs:enumeration value="TN" />
    <xs:enumeration value="MP" />   
  </xs:restriction>
</xs:simpleType>

然后为我们想要的三种不同类型的地址定义三种不同的复杂类型。我假设英国地址没有获得“州”属性。

<xs:complexType name="US-address">
  <xs:attribute name="street" type="xs:string" use="required"/>
  <xs:attribute name="city" type="xs:string" use="required"/>
  <xs:attribute name="state" type="US-states"/>
  <xs:attribute name="country" type="xs:NMTOKEN" use="required"/>
</xs:complexType>
<xs:complexType name="UK-address">
  <xs:attribute name="street" type="xs:string" use="required"/>
  <xs:attribute name="city" type="xs:string" use="required"/>
  <xs:attribute name="country" type="xs:NMTOKEN" use="required"/>
</xs:complexType>
<xs:complexType name="IN-address">
  <xs:attribute name="street" type="xs:string" use="required"/>
  <xs:attribute name="city" type="xs:string" use="required"/>
  <xs:attribute name="state" type="IN-states"/>
  <xs:attribute name="country" type="xs:NMTOKEN" use="required"/>
</xs:complexType>

现在我们根据'country'的值将address元素绑定到其中一个元素:

<xs:element name="address">
  <xs:alternative test="@country='US'" type="US-address"/>
  <xs:alternative test="@country='IN'" type="IN-address"/>
  <xs:alternative test="@country='UK'" type="UK-address"/>
  <xs:alternative type="xs:error"/>
</xs:element>

备选方案按顺序进行测试,第一个测试评估为true的方法指定类型。最后一个替代方法(没有测试属性)提供了一个默认值,在这种情况下是错误类型(没有元素或属性对错误类型有效)。