XML模式中的复杂断言

时间:2014-05-29 02:23:55

标签: xml xsd assert restriction

<xs:complexType name="scene">
    <xs:sequence>
        <xs:element name="subtitle" type="subtitle" minOccurs="0"/>
        <xs:choice maxOccurs="unbounded">
            <xs:element name="speech" type="speech"/>
            <xs:element name="stagedir" type="stagedir"/>
            <xs:element name="subhead" type="subhead"/>
        </xs:choice>
    </xs:sequence>
    <xs:attribute name="title" use="required"/>
</xs:complexType>

<xs:complexType name="speech">
    <xs:sequence>
        <xs:element name="line" type="line"/>
    </xs:sequence>
    <xs:attribute name="persona" use="required"/>
    <xs:attribute name="actorID" use="required"/>
</xs:complexType>  

是学校游戏的场景。因此,一个演员可以描绘多个人物(角色)。同样,许多参与者可能共享一个角色的行。但要确保这不会失控。必须有约束来检查在一个场景元素中,一个actor不能是两个字符,因为这可能会导致舞台上出现问题。一个演员显然不能自言自语。虽然演员可以是不同场景中的其他人(元素)。

所以,如果actorID = 15是这个场景中的角色'C',他不能是这个场景的任何其他角色,但是actorID = 17也可以是角色'C'。

1 个答案:

答案 0 :(得分:2)

欢迎使用Stack Overflow。

您没有明确说明您的问题是什么;我想这是“为什么我试图制定这种约束不起作用?” - 这很难回答,因为你没有向我们展示你尝试过的东西 - 或者更普遍的是“我如何制定一个断言来检查这个约束?” (为了将来参考,请注意Stack Overflow读者倾向于对表明尝试自行解决问题的问题做出更积极的反应。)

您对约束的表述(在一个场景元素中,一个actor不能是两个字符)已经采用易于使用XSD 1.1断言表达的形式。要使其工作,您需要了解XPath 2.0量化表达式(使用关键字everysatisifiessomesatisfies的表达式。您将无法了解所有关于他们在这里,但应该很容易使用关键字或术语“量化表达”来查找它们。

首先:断言在哪里? XSD 1.1断言与类型相关联,并且可以使用XPath表达式指向该类型的实例中的节点,但不指向任何其他节点。因此断言不能在actorIDpersona属性上,也不能在speech元素上,因为断言必须在树中向上指向{{1}元素。因此,您需要在scene元素上进行断言 - 即在复杂类型scene中。

它应该说什么?稍微改写一下:在这个场景中,每个演员必须扮演最多一个角色 - 因为我们只会谈论场景中出现的actorID,所以我们不必担心关于扮演零人物的actorID。所以:在这个场景中,speech / @ actorID的每个值必须与一个语音/角色的值完全相关联。断言的大纲可以是

scene

仍需要弄清楚如何将句子形式化此演员只扮演一个角色,或者此actorID值只与一个角色值相关联。我们可以使用

获取场景中的所有角色属性
every $actor in speech/@actorID 
satisfies
(: this actor plays only one role in this scene :)

我们可以通过这种方式将集合限制为与给定的actorID ./speech/@persona 相关联的集合:

$actor

我们想要应用于这组角色属性的约束很简单:它们都应该具有相同的值。或者,等效地:该集合必须不能有多个不同的值。也就是说:当我们将./speech[@actorID = $actor]/@persona 函数应用于这组值时,我们应该得到一个单例列表。所以:

distinct-values

因此可以制定整个断言:

count(
  distinct-values(
    ./speech[@actorID = $actor]/@persona
  )
) eq 1

将它放在(: every actor ID in this scene is associated with exactly one persona in this scene :) every $actor in ./speech/@actorID satisfies count( distinct-values( ./speech[@actorID = $actor]/@persona ) ) eq 1 元素的test属性中,将该断言添加到复杂类型定义中,然后就完成了。 (好吧,实际上,制定了这个,你可以立刻想到“好吧,等一下。我们难道不应该确保任何一个角色只能由一个演员在一个场景内或整个剧中演奏吗?”我似乎记得读过有三个演员演奏哈姆雷特的作品,所有人都在同一时间在舞台上,每个人都采取了一些角色的线条。但也许你所描述的学校戏剧不会采用这种前卫的方法。即使他们这样做 - 哈姆雷特的演讲必须在扮演哈姆雷特的演员之间分配,这可能意味着哈姆雷特的角色被分为三个人。)但那个只是这个人的镜像;我会把它留给你作为练习。