在XSD中,如何显示元素只能在具有特定属性的父元素中?

In XSD, how do I show that an element can only be in a parent with a certain attribute?

我正在尝试记录其他人的手写代码 XML,我希望 XSD 能帮助我做到这一点。然而,我被无知所阻碍:我还不能保证 XSD 对整个事情都有效。 (请随时告诉我某些东西是糟糕的编码风格,但我只是文档编写者,而不是开发人员。)

反正我的情况是:

<items>
  <item name="foo">
    <coolThing>wah!</coolThing>
  </item>
  <item name="bar">
    <needfulThing>address</needfulThing>
  </item>
</items>

(当然是实际条款。)<coolThing>元素只能出现在<item name="foo">容器中,<needfulThing>元素只能出现在[=16=中]容器。

如何在 XSD 中指定它?我正在查看的教程方便地忽略了这一点。

是否像将分类元素定义为属性声明的子元素一样简单:

<xs:attribute name="foo" type="xs:string">
  <xs:element name="coolThing" type="xs:string"/>
</xs:attribute>

(为清楚起见,省略了一些内容。)当然,这不会让我轻易地指定 <coolThing> 可以同时出现在 <item name="foo"><item name="baz"> 元素中,如果出现这种情况。

还是我遗漏了什么? (很有可能。)

是的,您从根本上忽略了 XSD(以及其他 XML 模式)旨在将元素与基于 name[= 的类型相关联40=] 元素的属性,而不是元素的属性。

因此,使用 itemobjectthing 等通过 name 等属性区分的过于通用的元素被视为反模式. XSD 1.1 有一个允许表达此类约束的断言机制,但实际上你会通过断言人为地重新实现自然包含约束——而不是你想要的地方。

具体来说,不是一般地设计 XML 元素,

<item name="foo"/>

让它们的元素名称传达它们的性质:

<foo/>

然后您会发现 XSD 1.0 中可用的普通内容模型足以表达您的包含限制。


更新:Michael Kay 让我想起了另一个 XSD 1.1 机制,它不如断言强大,但如果您只需要改变每个属性的类型,它更适合值:条件类型分配...

如果您坚持使用过于通用的元素名称并寻求在事后编写模式,在 XSD 1.1 的断言之前,请考虑 XSD 1.1 的 Conditional Type Assignment,它允许根据属性值分配类型。

可在此处找到完整的工作示例:

您可以使用 XSD 1.1 和 类型替代品 来执行此操作。参见示例 XSD 1.1 alternative usage issue。此功能明确设计用于执行您想要的操作 - 使元素的类型取决于属性的值,而不是元素的名称。

但是您需要 XSD 1.1 处理器。我知道三个:Altova、Saxon 和 Apache Xerces。许多广泛使用的 XSD 处理器,例如 Microsoft 的处理器,从未更新到 XSD 1.1。