1

在 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 types 声明为 global level elements,虽然这完全限制了 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 约束再次工作)?如果您认为我最好选择列出的选项之一,也请留下答案。

4

1 回答 1

0

使用顶级组。

这就像您的最后一个要点,但您可以在<xs:group ref=..."/>每次需要时引用它,而不是重复选择(或者您可能是这个意思)。

<xs:complexType name="parentType">
  <xs:group ref="AChild" minOccurs="1" maxOccurs="unbounded" />
</xs:complexType>

<xs:group name="AChild">
  <xs:choice>
    <xs:element name="AConcreteChild" type="AConcreteChild_type" />
    <xs:element name="AnotherPossibleConcreteChild" type="AnotherPossibleConcreteChild_type" />
  </xs:choice>
</xs:group>

顺便说一句:我也觉得这更清楚,因为选项在 xsd 中组合在一起,因此您不必扫描具有相同替换组的元素声明。

于 2012-12-28T05:18:49.567 回答