繁体   English   中英

XML模式设计:根据元素在文档中的位置来限制元素的出现

[英]XML Schema Design: restrict the occurrence of an element according to its position in the document

您好,我遇到了一个有关根据元素在文档中的位置来限制元素出现的问题。 实际上,“位置”可能不是一个恰当的术语,但我想不出一种更好的方式来概括问题。 无论如何,让我解释一下业务逻辑。 该模式将设计用于播放脚本。 在戏剧中,一个演员可以扮演多个角色。 一部戏包含许多场景,在一个场景中,有几次舞台指示(Enter / Exit)的出现,在两个舞台指示之间,演员发表讲话。 一个示例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>

这里要求的限制是,如果一个演员扮演多个角色,则不允许两个角色同时在舞台上互相交谈(如果一个演员扮演多个角色,则该演员的角色不能出现在舞台上)。舞台)。 例如,亚历克斯(Alex)同时演奏超人和蝙蝠侠,由于它们是由同一个人演奏,因此它们不能同时出现在舞台上。 当前,该架构如下所示:

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

那么如何在模式中实现这种限制呢?

要强制执行以下规则:对于每个<SCENE>任何具有相同actorID属性的<SPEAKER>元素都必须包含相同的文本,您可以使用XPath 2.0断言声明SCENETYPE ,如下所示:

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

这将在支持<xs:assert> XSD 1.1中工作。 您也可以使用XSD 1.0的Schematron扩展来执行类似的操作。

有了这个限制,由于存在一致的映射,因此该块将生效: 1 = Superman2 = 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包含SupermanBatman

<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 ,例如,当您在<STAGEDIR>列出<PERSONA>元素时,您可以在那里检查一致性,而不是检查整个场景。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM