您好我遇到了一个问题,即根据元素在文档中的位置来限制元素的出现。实际上"位置"可能不是一个合适的术语,但我无法想出一个更好的方法来总结问题。 无论如何,让我解释一下业务逻辑。该架构将设计用于播放脚本。在剧中,一个演员可以扮演多个角色。一个游戏包含许多场景,在一个场景中,有几个阶段方向(进入/退出),两个阶段方向之间,演员发表演讲。示例xml实例如下所示:
<PLAY>
<CAST>
<ROLE>
<ACTOR id="1">Alex</ACTOR>
<PERSONA>Superman</PERSONA>
</ROLE>
<ROLE>
<ACTOR id="1">Alex</ACTOR>
<PERSONA>Batman</PERSONA>
</ROLE>
<ROLE>
<ACTOR id="2">John</ACTOR>
<PERSONA>Hulk</PERSONA>
</ROLE>
</CAST>
<TITLE>Lego Movie</TITLE>
<SCENE>
<TITLE>SCENE I</TITLE>
<STAGEDIR>Enter Superman, Hulk</STAGEDIR>
<SPEECH>
<SPEAKER actorID="1">Superman</SPEAKER>
<LINE>Hahaha</LINE>
</SPEECH>
<SPEECH>
<SPEAKER actorID="2">Hulk</SPEAKER>
<LINE>Hahaha</LINE>
</SPEECH>
<STAGEDIR>Exit Superman, Enter Batman</STAGEDIR>
<SPEECH>
<SPEAKER actorID="1">Batman</SPEAKER>
<LINE>Yo</LINE>
</SPEECH>
<SPEECH>
<SPEAKER actorID="2">Hulk</SPEAKER>
<LINE>Yo</LINE>
</SPEECH>
</SCENE>
</PLAY>
这里要求的限制是,如果演员扮演多个角色,则不允许两个角色同时在舞台上互相交谈(如果一个演员扮演多个角色,一个演员&#39 ; s persona不能同时出现在舞台上)。例如亚历克斯正在扮演超人和蝙蝠侠,他们不能同时出现在舞台上,因为他们是由同一个人扮演的。 目前架构如下:
<xs:complexType name="PLAYTYPE">
<xs:sequence>
<xs:element ref="CAST"/>
<xs:element ref="TITLE"/>
<xs:element ref="SCENE"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="CASTTYPE">
<xs:sequence>
<xs:element ref="ROLE" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="ROLETYPE">
<xs:sequence>
<xs:element ref="ACTOR"/>
<xs:element ref="PERSONA"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="SCENETYPE">
<xs:sequence>
<xs:element ref="TITLE"/>
<xs:element ref="STAGEDIR"/>
<xs:element ref="SPEECH" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="ACTORTYPE">
<xs:sequence>
<xs:element ref="NAME"/>
</xs:sequence>
<xs:attributeGroup ref="attlist.ACTOR"/>
</xs:complexType>
<xs:complexType name="STAGEDIRTYPE" mixed="true">
<xs:sequence>
<xs:element minOccurs="1" maxOccurs="unbounded" ref="PERSONA"/>
</xs:sequence>
<xs:attributeGroup ref="attlist.SPEAKER"/>
</xs:complexType>
<xs:complexType name="SPEECHTYPE">
<xs:sequence>
<xs:element ref="SPEAKER"/>
<xs:element ref="LINE"/>
</xs:sequence>
<xs:attributeGroup ref="attlist.ACTOR"/>
</xs:complexType>
<xs:complexType name="SPEAKERTYPE" mixed="true">
<xs:attributeGroup ref="attlist.SPEAKER"/>
</xs:complexType>
<xs:element name="PLAY" type="PLAYTYPE"/>
<xs:element name="CAST" type="CASTTYPE"/>
<xs:element name="ROLE" type="ROLETYPE"/>
<xs:element name="ACTOR" type="ACTORTYPE"/>
<xs:element name="SCENE" type="SCENETYPE"/>
<xs:element name="STAGEDIR" type="STAGEDIRTYPE"/>
<xs:element name="SPEAKER" type="SPEAKERTYPE"/>
<xs:element name="TITLE" type="xs:string"/>
<xs:element name="PERSONA" type="xs:string"/>
<xs:element name="NAME" type="xs:string"/>
<xs:element name="LINE" type="xs:string"/>
<xs:attributeGroup name="attlist.ACTOR">
<xs:attribute name="id" use="required"/>
</xs:attributeGroup>
<xs:attributeGroup name="attlist.SPEAKER">
<xs:attribute name="actorID" use="required"/>
</xs:attributeGroup>
那么如何在架构中实现这种限制呢?
答案 0 :(得分:0)
要强制执行以下规则:每个<SCENE>
具有相同<SPEAKER>
属性的actorID
元素必须包含相同的文本,您可以使用XPath声明SCENETYPE
2.0断言,如下图所示:
<xs:complexType name="SCENETYPE">
<xs:sequence>
<xs:element ref="TITLE"/>
<xs:element ref="STAGEDIR"/>
<xs:element ref="SPEECH" maxOccurs="unbounded"/>
</xs:sequence>
<xs:assert test="every $speakerId in SPEECH/SPEAKER/@actorID
satisfies
(every $speaker in SPEECH/SPEAKER[@actorID=$speakerId]
satisfies
(SPEECH/SPEAKER[@actorID=$speakerId])[1] = $speaker)"/>
</xs:complexType>
这适用于 XSD 1.1 ,它支持<xs:assert>
。您也可以使用XSD 1.0的 Schematron 扩展来执行此类操作。
通过此限制,此块将验证,因为存在一致的映射:1 = Superman
,2 = Hulk
:
<SCENE>
...
<SPEECH id="1">
<SPEAKER actorID="1">Superman</SPEAKER>
<LINE>Hahaha</LINE>
</SPEECH>
<SPEECH id="2">
<SPEAKER actorID="2">Hulk</SPEAKER>
<LINE>Hahaha</LINE>
</SPEECH>
<SPEECH id="3">
<SPEAKER actorID="1">Superman</SPEAKER>
<LINE>Yo</LINE>
</SPEECH>
<SPEECH id="4">
<SPEAKER actorID="2">Hulk</SPEAKER>
<LINE>Yo</LINE>
</SPEECH>
</SCENE>
但是这会失败验证,因为1
包含Superman
以及Batman
:
<SCENE>
<TITLE>SCENE I</TITLE>
<STAGEDIR actorID="0"><PERSONA>Superman</PERSONA><PERSONA>Hulk</PERSONA><PERSONA>Batman</PERSONA></STAGEDIR>
<SPEECH id="1">
<SPEAKER actorID="1">Superman</SPEAKER>
<LINE>Hahaha</LINE>
</SPEECH>
<SPEECH id="2">
<SPEAKER actorID="2">Hulk</SPEAKER>
<LINE>Hahaha</LINE>
</SPEECH>
<SPEECH id="3">
<SPEAKER actorID="1">Batman</SPEAKER>
<LINE>Yo</LINE>
</SPEECH>
<SPEECH id="4">
<SPEAKER actorID="2">Hulk</SPEAKER>
<LINE>Yo</LINE>
</SPEECH>
</SCENE>
如果您仍在设计此架构,更好的选择是在<STAGEDIR>
元素中检查此一致性,因为 可以使同一个actor成为两个字符如果它退出并在不同时刻返回,则在同一场景中。由于<PERSONA>
可以由不同的演员扮演,您可能想要某种方式来关联currentActorId
,例如,当您在<PERSONA>
中列出<STAGEDIR>
元素时你可以检查那里的一致性,而不是检查整个场景。