xs:sequence
和的结合xs:choice
是这里的关键,请记住,将两者结合的方式很重要(见下文为什么)。正确的方法(至少基于我设法找出的)是像这样表达构建 XSD:
<xs:complexType name="itemType">
<xs:sequence>
<xs:element name="Price" type="xs:integer" />
<xs:choice minOccurs="0">
<xs:sequence>
<xs:element name="Ratio" type="xs:float" />
<xs:element name="MaxPrice" type="xs:integer" />
</xs:sequence>
</xs:choice>
</xs:sequence>
</xs:complexType>
<xs:element name="Item" type="my:itemType" />
这样,您可以选择包含固定的元素序列,这正是我们所寻找的。
(如果你找到了你要找的东西,你可以在这里停止阅读。接下来的内容仅仅是解释似乎还有哪些其他方法以及为什么它们不起作用)
有人可能想知道(这也是我从其他地方启发的最初想法)两个固定序列的固定选择也可能起作用,并且可以作为一种广泛可重用的模式。尽管在某些情况下确实如此,但这并不是其中之一。观察:
<xs:complexType name="itemType">
<xs:choice>
<xs:sequence>
<xs:element name="Price" type="xs:integer" />
</xs:sequence>
<xs:sequence>
<xs:element name="Price" type="xs:integer" />
<xs:element name="Ratio" type="xs:float" />
<xs:element name="MaxPrice" type="xs:integer" />
</xs:sequence>
</xs:choice>
</xs:complexType>
<xs:element name="Item" type="my:itemType" />
看起来不错吧?好吧,显然不是 - 完整的项目不会通过!验证器迭代地落入第一选择,验证Price
元素并失败,说明以下Ratio
元素是意外的。
好吧,一个明显的补救措施出现了 - 让我们切换选择:
<xs:complexType>
<xs:choice>
<xs:sequence>
<xs:element name="Price" type="xs:integer" />
<xs:element name="Ratio" type="xs:float" />
<xs:element name="MaxPrice" type="xs:integer" />
</xs:sequence>
<xs:sequence>
<xs:element name="Price" type="xs:integer" />
</xs:sequence>
</xs:choice>
</xs:complexType>
<xs:element name="Item" type="my:itemType" />
这似乎工作正常,直到您决定扩展可怜的Item
元素(也许 Item 元素的其他一些用法也可能会导致麻烦)。
我试过例如:
<xs:complexType name="DiscountedItem">
<xs:complexContent>
<xs:extension base="my:itemType">
<xs:sequence>
<xs:element name="Discount" type="xs:integer" />
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
如果你尝试这个,你会在DiscountedItem
有或没有 { Ratio
, MaxPrice
} 子元素的情况下失败,这取决于你是否切换了选择。
尽管如此,这得出的结论是,对于这个用例,使用第一个提到的“包含固定序列的可选选项”会更好。我发现这很难,所以你不必:)