Dynamic enumeration restriction using XSD 1.1

后端 未结 1 381
有刺的猬
有刺的猬 2020-12-10 07:23

I am trying to create a schema definition using XSD 1.1 in which outcome of one element is dependent on other. For example, I have drop-down for list of countries and list o

相关标签:
1条回答
  • 2020-12-10 07:32

    You're getting close.

    In XSD 1.1, assertions can only look down into the subtree, not up or over, so if you want to use assertions here, you will want to put them not in the type for 'state' but in the type for 'address':

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

    A different approach (also in XSD 1.1) is to use conditional type assignment. This allows an element to be assigned different types based on XPath expressions which can refer to its elements (but not its children). If we move country and state to attributes (and then, for consistency, move street and city to attributes as well), we could use conditional type assignment this way. First, define the various simple types we want for state:

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

    Then define three different complex types for the three different kinds of addresses we want. I'm assuming for illustration that UK addresses don't get a 'state' attribute.

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

    Now we bind the address element to the correct one of these based on the value of 'country':

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

    The alternatives are tested in order, and the first one whose test evaluates to true assigns the type. The last alternative (without a test attribute) provides a default, which in this case is the error type (no elements or attributes are valid against the error type).

    0 讨论(0)
提交回复
热议问题