【问题标题】:Restrict an XML Schema element to contain a more specific type限制 XML Schema 元素以包含更具体的类型
【发布时间】:2011-04-06 07:50:06
【问题描述】:

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

<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 类型,它保存着模组列表,如下所示:

<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 删除了一些与问题无关的架构信息。还是有点长,不好意思……

【问题讨论】:

  • 类型扩展没有错。关于基本类型的限制,我想你在找abstract element

标签: xml xsd schema


【解决方案1】:

如果您使用替代组和可能的抽象元素,您应该能够执行以下操作:

<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>

【讨论】:

  • 谢谢,这很有用!那么还有一个问题,是否有可能派生一种新类型,将序列限制为仅使用特定的替换组?或者,是否可以将 Mod 元素重新定义为 mods:Fallout3ModType 以有效地覆盖原始元素?
  • 我认为第一个问题实际上是这里有什么。 ModsType 只能接受从 ModAbstract 派生或在其替换组中的项目。
猜你喜欢
  • 2021-06-28
  • 1970-01-01
  • 2014-07-05
  • 2010-09-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多