限制XML Schema元素包含更特定的类型



我有一个包含以下类型的模式,它的设计本质上是保存与游戏模型相对应的元素列表:

<xs:complexType name="OrderedModTemplateType">
    <xs:sequence minOccurs="1" maxOccurs="1">
        ...
        <xs:element name="Mods" type="mods:ModsType" minOccurs="1">
            <xs:key name="modKey">
                <xs:selector xpath="Mods"/>
                <xs:field xpath="@id"/>
            </xs:key>
        </xs:element>
    </xs:sequence>
    ...
</xs:complexType>

ModsType类型,保存mod列表,看起来像这样:

<xs:complexType name="ModsType">
 <xs:sequence>
   <xs:element name="Mod" type="ModType" maxOccurs="unbounded" />
 </xs:sequence>
</xs:complexType> 

这是ModType类型,ModsType期望作为它的子类型:

<xs:complexType name="ModType">
    <xs:sequence minOccurs="0" maxOccurs="1">
        ...
    </xs:sequence>
    ...
    <xs:anyAttribute/>
</xs:complexType>

我想创建一个更具体的OrderedModTemplateType,与上面发布的完全相同,除了Mods元素中的Mod元素将被要求是一个更具体的衍生类型的Mod,特别是Fallout3ModType:

<xs:complexType name="Fallout3ModType">
    <xs:complexContent>
        <xs:extension base="mods:ModType">
            <xs:attribute name="requiresFose" type="xs:integer" default="0" />
            <xs:attribute name="foseVersion" type="xs:string" />
        </xs:extension>
    </xs:complexContent>
</xs:complexType>

因此,我知道可以通过在元素中指定xsi:type来使用Fallout3ModType类型的Mod元素,但是如果我希望元素只包含Fallout3ModType类型的元素,而不包含其他特定类型的元素,例如仅包含ModType(这是默认接受的类型),该怎么办?

我不想这样做:

<Mods>
  <Mod xsi:type="Fallout3ModType" ...>
    ...
  </Mod>
  <Mod xsi:type="Fallout3ModType" ...>
    ...
  </Mod>
</Mods>

我可以扩展ModsType到Fallout3ModsType,它只接受Fallout3ModType的Mod元素,而不仅仅是ModType?如果是这样,我可以使用如下命令:

<Mods xsi:type="Fallout3ModsType">
  <Mod ...>
    ...
  </Mod>
  <Mod ...>
    ...
  </Mod>
</Mods>

或者,我可以以某种方式扩展OrderedModTemplateType有类型Fallout3ModsType的Mods元素,而不是ModsType?在这种情况下,我可以使用新类型来简化XML中的使用:

<Mods>
  <Mod ...>
    ...
  </Mod>
  <Mod ...>
    ...
  </Mod>
</Mods>

我真的在努力弄清楚我是否在正确的方式,或者如果我错过了什么…

这似乎是有效的,但我有一种感觉,这是不对的:

<xs:complexType name="Fallout3ModsType">
    <xs:complexContent>
        <xs:extension base="mods:ModsType">
            <xs:sequence>
                <xs:element name="Mod" type="Fallout3ModType" minOccurs="0" maxOccurs="unbounded"/>
            </xs:sequence>
        </xs:extension>
    </xs:complexContent>
</xs:complexType>

这不是在本质上定义另一个独立的Mod元素,只是在类型上不同于原来的Mod元素吗?如果这是合法的,那么解析器如何在不深入查看嵌套元素的情况下知道我引用的是哪个元素呢?

或者也许我在用更具体的类型重写类型的正确方法上犯了错误?我怀疑……

更新2 删除了一些与问题无关的模式信息。还是有点长,抱歉……

如果您使用一个substitutionGroup和一个潜在的抽象元素,您应该能够做如下的事情:

<Mods>
    <Mod />
    <Fallout3Mod />
    <Mod />
</Mods>

示例xsd:

<xs:complexType name="ModsType">
    <xs:sequence>
        <xs:element ref="mods:ModAbstract" maxOccurs="unbounded" ></xs:element>
    </xs:sequence>
</xs:complexType>
<xs:complexType name="ModType">
    <xs:sequence minOccurs="0" maxOccurs="1"> </xs:sequence>
    <xs:anyAttribute/>
</xs:complexType>

<xs:complexType name="Fallout3ModType">
    <xs:complexContent>
        <xs:extension base="mods:ModType" />
    </xs:complexContent>
</xs:complexType>
<xs:element name="ModAbstract" abstract="true" type="mods:ModType" />
<xs:element name="Mod"  type="mods:ModType" substitutionGroup="mods:ModAbstract" ></xs:element>
<xs:element name="Fallout3Mod"  type="mods:Fallout3ModType" substitutionGroup="mods:ModAbstract"></xs:element>

最新更新