使用派生元素替换时保留单根节点定义

时间:2012-12-27 23:52:40

标签: xml xsd root-node

在XSD架构中,您cannot declare an element as the only valid root node为您的文档 这是一个PITA,但我知道它。

多年来,我只会做链接答案中建议的内容 - 只定义<simpleType><complexType> s,在全局级别定义的唯一<element>是我想要的根节点。

但是,我目前正在对我的XSD / XSLT代码库进行很好的重构。我想要做的一件事是将某个元素限制为仅从所需类型派生的元素,前提是这些派生词可以有不同的节点名称:

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

其中AChild是一个抽象基类型,其他类型将使用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只适用于在全局级别声明的元素。所以现在我有一堆先前的内部type被声明为全局级element,虽然这完全限制了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>中之前)。

我的问题是,有没有其他方法可以使any-derived-element约束工作而不声明多个全局级<element>(以便唯一的根节点约束再次起作用)?如果您认为我最好选择一个列出的选项,请留下答案。

1 个答案:

答案 0 :(得分: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>
BTW:我也觉得这个更清楚,因为选择在xsd中组合在一起,所以你不必扫描具有相同替换组的元素声明。