在 XSD 模式中,您不能将元素声明为文档的唯一有效根节点。
这是一个 PITA,但我知道。
多年来,我只会做链接答案中建议的事情——只定义<simpleType>
s 和<complexType>
s,唯一<element>
在全局级别定义的是我想要的根节点。
但是,我目前正在对我的 XSD/XSLT 代码库进行很好的重构。我想做的一件事是将某个元素限制为仅从所需类型派生的元素,前提是这些派生可以具有不同的节点名称:
<xs:complexType name="parentType">
<xs:sequence>
<xs:element ref="AChild" minOccurs="1" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
whereAChild
是一个抽象基类型,其他类型将使用它派生substitutionGroup
:
<xs:complexType name="child_base" abstract="true">
...
</xs:complexType>
<xs:element name="AChild" type="child_base" abstract="true" />
<xs:element name="AConcreteChild" substitutionGroup="AChild" >
<xs:complexType>
<xs:complexContent>
<xs:extension base="child_base">
...
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
<xs:element name="AnotherPossibleConcreteChild" substitutionGroup="AChild" >
<xs:complexType>
<xs:complexContent>
<xs:extension base="child_base">
...
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
这里的问题是这个substitutionGroup
东西只适用于在全局级别声明的元素。所以现在我有一堆以前的 internal type
s 声明为 global level element
s,虽然这完全限制了 s 的可能子节点parentType
,但这也意味着如果任何现在全局子节点作为根元素提供,验证将成功,我不想要。
我考虑过的选项包括:
- 放弃
substitutionGroup
继承,将所有可能的子项移动到单独的命名空间,然后使用<xsd:any namespace="that namespace" />
. 感觉还可以,但我不喜欢额外的命名空间和定义更差的约束。 - 忽略 XSD 级别的问题,检查使用 XSD 模板的代码中的根节点名称和命名空间。我不喜欢这里打破关注点分离,因为在我的设计中,XSD 文件是调用代码的黑盒,我宁愿不引入对节点 QName 的硬编码依赖。
引入一个原则,根据该原则,总会有两个“主要”XSD 模式。一个将以通常的方式验证节点(我目前拥有的验证),另一个将仅包含最宽松形式的顶级节点的定义:
<xs:complexType name="parentType"> <xs:sequence> <xs:any namespace="##any" processContents="skip" /> </xs:sequence> <xs:anyAttribute namespace="##any" processContents="skip" /> </xs:complexType> <xs:element name="TheRootNode" type="parentType" />
然后当且仅当两个模式都验证时,我的文档才是正确的。
我不喜欢这里的是我不确定这对最佳实践的违反程度。退出重构并保留我之前的内容(以及在我手动列出所有可能的子项之前
<xs:choice>
)。
我的问题是,有没有其他方法可以在不声明多个 global-level<element>
的情况下使 any-derived-element 约束工作(以便 only-root-node 约束再次工作)?如果您认为我最好选择列出的选项之一,也请留下答案。