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



我正在尝试记录别人手工编码的XML,我希望XSD能帮助我做到这一点。然而,我的无知阻碍了我:我还不能保证XSD将适用于所有事情。(如果是糟糕的编码风格,请随意告诉我,但我只是文档管理员,不是开发人员。)

无论如何,情况是我有:

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

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

我如何在XSD中指定这个?我正在看的教程很方便地省略了这一点。

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

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

(为了清楚起见,省略了一些内容。)当然,如果<item name="foo"><item name="baz">元素同时出现<coolThing>,这就不容易了。

还是我错过了什么?(很有可能)

是的,您忽略了XSD(以及其他XML模式)的基本设计是基于元素的名称而不是元素的属性将元素与类型关联起来。

由于这个原因,使用过于通用的元素,如itemobjectthing,通过属性(如name)来区分,被认为是一种反模式。XSD 1.1有一个断言机制,允许表达这样的约束,但实际上,您将通过断言人为地重新实现自然的包含约束——这不是您想要的。

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

<item name="foo"/>

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

<foo/>

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


更新:Michael Kay提醒我另一种XSD 1.1机制,它没有断言那么强大,但如果您只需要更改每个属性值的类型,则更适合:条件类型赋值…

如果您被过于泛型的元素名称所限制,并且在XSD 1.1断言之前寻求事后编写模式,请考虑XSD 1.1的条件类型赋值,它允许根据属性值分配类型。

一个完整的工作示例可以在这里找到:

  • 如何使用条件类型赋值使类型依赖于属性值

您可以使用XSD 1.1完成此操作,并使用类型替代. 例如,请参阅XSD 1.1的替代使用问题。这个特性被明确地设计成你想要的——使元素的类型依赖于一个属性的值,而不是元素的名称。

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

最新更新