xsd 两个xsd整合
xsd:choice
是一种较为常见的XML构造。 但是,将xsd:choice
映射到编程语言并不总是那么简单。 例如,JAX-RPC规范定义的Web服务的Java映射没有提供从xsd:choice
到Java的显式映射。 每当JAX-RPC代码生成器在类型定义中遇到xsd:choice
时,它都会将该类型映射到javax.xml.soap.SOAPElement
。 SOAPElement
是SAAJ API的一部分,它不是一个非常用户友好的API。
您可以采取一些措施以获得更好的API。 如果您能够更改XML模式,一个不错的选择是用多态替换xsd:choice
。
xsd:choice
和多态 多态性的意思是“许多形状”。 例如,可以使用基本类型声明方法参数。 调用该方法时,该参数的实例是该类型的特定扩展。
您可以类似地描述xsd:choice
。 可以使用描述所有可能选择的类型声明方法参数。 调用该方法时,该参数的实例将包含特定的选择。
实际的单词是不同的,但是它们的含义本质上是相同的。
xsd:choice
类型映射为多态类型 要将典型选择类型转换为一组多态类型,需要在给定选择类型C下执行以下操作,其中包含选择c1..cn:
P
E of P
的扩展类型E of P
其中包含c的元素。 用示例理解概念总是比较容易的。 看一下付款选项的声明。 清单1是选择类型。 清单2是对一组多态类型的转换。
<complexType name="Payment">
<sequence>
<element name="amount" type="int"/>
<choice>
<element name="cash" nillable="true" type="string"/>
<element name="check" type="tns:Check"/>
<element name="credit" type="tns:Credit"/>
</choice>
</sequence>
</complexType>
<complexType name="Check">
<sequence>
<element name="checkNo" type="int"/>
</sequence>
</complexType>
<complexType name="Credit">
<sequence>
<element name="cardNo" type="string"/>
<element name="expiration" type="date"/>
</sequence>
</complexType>
<complexType abstract="true" name="Payment">
<sequence>
<element name="amount" type="int"/>
</sequence>
</complexType>
<complexType name="CashPayment">
<complexContent>
<extension base="tns:Payment">
<sequence>
<element name="cash" nillable="true" type="string"/>
</sequence>
</extension>
</complexContent>
</complexType>
<complexType name="CheckPayment">
<complexContent>
<extension base="tns:Payment">
<sequence>
<element name="check" type="tns:Check"/>
</sequence>
</extension>
</complexContent>
</complexType>
<complexType name="CreditPayment">
<complexContent>
<extension base="tns:Payment">
<sequence>
<element name="credit" type="tns:Credit"/>
</sequence>
</extension>
</complexContent>
</complexType>
多态支付示例比选择支付示例更为冗长。 这是因为XML并不是真正的面向对象的语言,并且将面向对象的功能应用于它并不是一件容易的事。 但这不应该阻止您。 您很可能会将XML映射到编程语言。 作为使用该特定编程语言的开发人员,您无需关心XML模式的外观。 您只需要关心该模式的语言映射是什么样。
唯一需要关心XML模式外观的时间是当您想要进行性能分析时。 例如,如果此架构是Web服务的一部分,则要比较这些类型的简单对象访问协议(SOAP)消息,以确定消息大小本身是否影响性能。 因此,让我们比较这两个变体的实例。 例如,假设我们希望以支票(1050号)付款,金额为10美元。 清单3显示了选择示例,清单4显示了多态示例。 (请注意,为了简化此示例,我忽略了名称空间和前缀。)
<payment>
<amount>10</amount>
<check>
<checkNo>1050</checkNo>
</check>
</payment>
<payment xsi:type="CheckPayment">
<amount>10</amount>
<check>
<checkNo>1050</checkNo>
</check>
</payment>
如您所见,清单4和清单5之间的唯一区别是多态实例包含类型信息。 尽管这值得注意,但通常并不重要。 实际上,它可以潜在地简化SOAP引擎的处理,因为该引擎从一开始就知道类型是什么,并预先选择了合适的反序列化器,而不必解析实例并检查choice元素的名称- -在这种情况下, check
-确定类型。
因此,使用多态替代并不比选择替代昂贵得多,它可以为您提供更加友好的语言映射。
xsd:choice
maxOccurs大于1的xsd:choice
绝大多数选择方案与上面显示的简单情况相似。 但choice 可能具有maxOccurs
属性大于1
。 映射是相似的,但是您需要一个额外的层来处理这种新类型的新数组方面。
P
P
的元素替换C中的选择,并携带从选择到新元素的maxOccurs
属性。 P
的扩展类型E
,其中包含c的元素。 例如,修改清单1中的Payment
类型,以在选择项上包含maxOccurs="unbounded"
属性。 (请参见清单5,其中的附加内容以粗体突出显示。)
(此类型的意思是一个人可以使用多种付款方式进行单笔付款:部分现金,部分支票,部分信用卡或任何组合。)
maxOccurs
选择付款 <complexType name="Payment">
<sequence>
<element name="amount" type="int"/>
<choice maxOccurs="unbounded">
<element name="cash" nillable="true" type="string"/>
<element name="check" type="tns:Check"/>
<element name="credit" type="tns:Credit"/>
</choice>
</sequence>
</complexType>
清单6显示了转换后的多态类型集。 清单2中的更改以粗体突出显示。
maxOccurs
多态支付 <complexType name="Payment">
<sequence>
<element name="amount" type="int"/>
<element name="option" type="PaymentOption" maxOccurs="unbounded"/>
</sequence>
</complexType>
<complexType abstract="true" name="PaymentOption">
<sequence/>
</complexType>
<complexType name="CashPayment">
<complexContent>
<extension base="tns:PaymentOption">
<sequence>
<element name="cash" nillable="true" type="string"/>
</sequence>
</extension>
</complexContent>
</complexType>
<complexType name="CheckPayment">
<complexContent>
<extension base="tns:PaymentOption">
<sequence>
<element name="check" type="tns:Check"/>
</sequence>
</extension>
</complexContent>
</complexType>
<complexType name="CreditPayment">
<complexContent>
<extension base="tns:PaymentOption">
<sequence>
<element name="credit" type="tns:Credit"/>
</sequence>
</extension>
</complexContent>
</complexType>
请注意, PaymentOption
类型没有自己的字段。 可能看起来有些奇怪,但是没有任何问题。 这是一种抽象类型,因此PaymentOption
实例将永远不存在。 只有它的扩展名可以存在。
请注意,您还可以应用maxOccurs
规则来转换典型选择示例。 但是,我希望您能看到简化的规则对典型情况的好处:您可以处理的间接层少了,类型少了一种。
xsd:choice
优势 与xsd:choice
相比,多态有两个主要优点xsd:choice
:可扩展性和类型指示。
就其性质而言,多态类型是可扩展的。 您可以根据需要选择任意数量的抽象基本类型扩展名,具体取决于您是否出于组织目的将这些扩展名扩展到多个.xsd文件中(一个组织可能仅接受现金和支票;另一个组织可能仅接受信用卡和在线支付)或者是否随着时间的推移添加新的。
但是xsd:choice
本身是不可扩展的。 如果要随时间添加选择,或者要在不同的.xsd文件中选择不同的选择集,则要么将所有可能的选择都定义为一个整体类型,然后让代码担心每种情况下可用的内容,要么您有很多选择包含相同选择选项的类型。 这些选项都不是特别可靠。 确实可以扩展选择类型并向扩展类型添加选择,但是为什么不进行全面的跨越并完全遵循多态模式,从而删除所有xsd:choice
用法?
在此付款示例中,选择之一是cash
。 您是否注意到这似乎是一个定义很奇怪的选择? 除了金额外,您还需要了解现金吗? 没有。 这就是为什么添加了属性nillable="true"
原因; 您可以给cash
元素一些价值,但这将毫无意义。 现金支付的实例可能类似于清单7。
<payment>
<amount>10</amount>
<cash xsi:isNil="true"/>
</payment>
您在这里只想说的是现金付款。 但是,在没有选择的情况下,没有办法表明这一点。
在清单2的CashPayment
类型中,我随身携带了cash
元素,因为我只是应用了转换规则,但实际上并不需要它。 您所需要的只是表明这是一种现金类型,仅此而已,并且由于多态性而已。 因此CashPayment
选项将扩展Payment
类型,但不添加任何新内容。 清单8显示了CashPayment
类型的改进版本。 清单9显示了这种类型的实例。
<complexType name="CashPayment">
<complexContent>
<extension base="tns:Payment">
<sequence/>
</extension>
</complexContent>
</complexType>
<payment xsi:type="CashPayment">
<amount>10</amount>
</payment>
在某些情况下, xsd:choice
类型不是要使用的最佳类型。 例如,当使用JAX-RPC映射规则将choice
类型映射到Java语言时,最终会得到Java映射,这不是非常用户友好的。 如果可以控制架构,则可能需要将包含xsd:choice
的类型转换为一组多态类型。 您不仅会得到一个更加用户友好的映射,而且多态性比xsd:choice
更健壮。
翻译自: https://www.ibm.com/developerworks/xml/library/ws-tip-xsdchoice/index.html
xsd 两个xsd整合