7

我的项目有以下 xsd 我正在尝试根据 Payment Method 枚举属性为 xmls ACH 和 CC 制作单个 xsd 如果付款方式是 Ach 则需要 ACHInfo 否则 CreditCardInfo ..

<xs:element name="PaymentMethod">
  <xs:simpleType>
    <xs:restriction base="xs:string">
      <xs:enumeration value="ACH"/>
      <xs:enumeration value="CreditCard"/>
    </xs:restriction>
  </xs:simpleType>
</xs:element>
<xs:element name="CreditCardInfo" minOccurs="0">
  <xs:complexType>
    <xs:all>
      <xs:element name="Cvv2No">
        <xs:simpleType>
          <xs:restriction base="xs:string">
            <xs:maxLength value="4"/>
          </xs:restriction>
        </xs:simpleType>
      </xs:element>
      <xs:element name="CardNumber">
        <xs:simpleType>
          <xs:restriction base="xs:string">
            <xs:maxLength value="20"/>
          </xs:restriction>
        </xs:simpleType>
      </xs:element>
     </xs:all>
  </xs:complexType>
</xs:element>
<xs:element name="ACHInfo" minOccurs="0">
  <xs:complexType>
    <xs:all>
      <xs:element name="RoutingNumber" nillable="false">
        <xs:simpleType>
          <xs:restriction base="xs:string">
            <xs:maxLength value="50"/>
          </xs:restriction>
        </xs:simpleType>
      </xs:element>
      <xs:element name="AccountNumber" nillable="false">
        <xs:simpleType>
          <xs:restriction base="xs:string">
            <xs:maxLength value="50"/>
          </xs:restriction>
        </xs:simpleType>
      </xs:element>
    </xs:all>
  </xs:complexType>
</xs:element>

任何人都可以为我提供解决方案,xsd 需要根据枚举值进行哪些更改以使属性成为必需的。

谢谢。

4

1 回答 1

18

四种解决方案,其中一些涉及重新考虑信息的 XML 表示:

XSD 1.1 断言

执行您所描述的最简单的方法是使用 XSD 1.1 并使用断言定义您想到的约束。你不说父元素叫什么;我称之为付款。我将使用tns目标命名空间的前缀。

<xs:element name="Payment">
  <xs:complexType>
    <xs:sequence>
      <xs:element ref="tns:PaymentMethod"/>
      <xs:choice>
        <xs:element ref="tns:ACHInfo" minOccurs="0"/>
        <xs:element ref="tns:CreditCardInfo" minOccurs="0"/>
      </xs:choice>
    </xs:sequence>
    <xs:assert test="(tns:PaymentType = 'ACH' and ./tns:ACHInfo)
                     or
                     (tns:PaymentType = 'CreditCard' 
                       and ./tns:CreditCardInfo)"/>
  </xs:complexType>
</xs:element>

XSD 1.1 条件类型赋值

出于某些目的,更好的方法是使用条件类型分配(也是 1.1 功能)进行付款。出于技术原因,这需要使 PaymentType 成为 Payment 的属性,而不是子属性:

<xs:element name="Payment">
  <xs:alternative test="@PaymentMethod='ACH'" 
                  type="tns:ACHPayment"/>
  <xs:alternative test="@PaymentMethod='CreditCard'" 
                  type="tns:CCPayment"/>
  <xs:alternative type="xs:error"/>
</xs:element>

这个声明意味着:如果 PaymentMethod 属性的值为“ACH”,那么元素 Payment 的类型为 tns:ACHPayment(我们稍后会定义)。否则,如果 PaymentMethod 的值为“CreditCard”,则 Payment 类型为 tns:CCPayment。否则,该元素无效。

我们将命名类型 ACHPayment 和 CCPayment 声明为包含适当的子项(并提供 PaymentMethod 属性)——我们可以内联它们,但命名它们会使条件类型分配模式更容易看到:

<xs:complexType name="ACHPayment">
  <xs:sequence>
    <xs:element ref="tns:ACHPayment"/>
  </xs:sequence>
  <xs:attribute name="PaymentMethod" type="tns:PaymentMethod"/>
</xs:complexType>

<xs:complexType name="CCPayment">
  <xs:sequence>
    <xs:element ref="tns:CreditCardPayment"/>
  </xs:sequence>
  <xs:attribute name="PaymentMethod" type="tns:PaymentMethod"/>
</xs:complexType>

出于同样的原因,我们为 PaymentMethod 属性的类型提供了一个命名声明:

<xs:simpleType name="PaymentMethod">
  <xs:restriction base="xs:string">
    <xs:enumeration value="ACH"/>
    <xs:enumeration value="CreditCard"/>
  </xs:restriction>
</xs:simpleType>

XSD 1.0,将支付方式移入内容模型

但是您不需要 XSD 1.1 来制作适用于您的应用程序的 XML;您只需要对您的设计进行不同的思考。如果您在元素名称中而不是在内容中选择付款类型,则很容易使 ACH 付款需要 ACHinfo 和信用卡付款需要 CreditCardInfo。而不是将父类型定义为:

<xs:complexType>
  <xs:sequence>
    <xs:element ref="tns:PaymentMethod"/>
    <xs:element ref="CreditCardInfo" minOccurs="0"/>
    <xs:element ref="ACHInfo" minOccurs="0"/>
  </xs:sequence>
</xs:complexType>

你可以这样声明:

<xs:complexType>
  <xs:choice>
    <xs:sequence>
      <xs:element ref="tns:ACHPayment"/>
      <xs:element ref="tns:ACHInfo" minOccurs="0"/>
    </xs:sequence>
    <xs:sequence>
      <xs:element ref="tns:CCPayment"/>
      <xs:element ref="tns:CreditCardInfo" minOccurs="0"/>
    </xs:sequence>       
  </xs:choice>
</xs:complexType>

两个标志元素 CCPayment 和 ACHPayment 可以是空元素:

<xs:complexType name="EMPTY">
  <xs:sequence/>
</xs:complexType>

<xs:element name='ACHPayment' type="tns:EMPTY"/>
<xs:element name='CCPayment' type="tns:EMPTY"/>

但就目前情况而言,这些都没有在设计中做任何工作。

XSD 1.0,简化

如果 ACHPayment 和 CCPayment 元素除了 (a) 发出支付使用这种方法的信号,以及 (b) 确保下面的兄弟是正确的,那么它们都没有做任何工作。 .

您可以通过这种方式轻松定义父元素:

<xs:element name="Payment">
  <xs:complexType>
    <xs:choice>
      <xs:element ref="tns:ACHInfo" minOccurs="0"/>
      <xs:element ref="tns:CreditCardInfo" minOccurs="0"/>
    </xs:choice>
  </xs:complexType>
</xs:element>

您仍然可以查看付款是 ACH 付款(Payment 元素的子元素名为 ACHInfo)还是信用卡付款(子元素名为 CreditCardInfo),您不再需要检查以确保详细信息与PaymentMethod 标志,因为 PaymentMethod 标志已消失。

更少的活动部件,更少的工作,更少的出错。

在这四种设计中,我认为这第四种可能是最好的。当然,您的里程可能会有所不同。

于 2013-05-28T16:03:14.447 回答