XSD 1.1检查另一个元素中是否存在属性

时间:2016-02-24 13:04:56

标签: xml xpath xsd xsd-validation xsd-1.1

我的XML文件Sequence和StateRelations中有2个主要部分。 Sequence部分定义为。 Transition元素应该根据下面定义的4个属性unqiue。

<xs:element name="Transition">
    <xs:complexType>
        <xs:sequence>
            <xs:element ref="Element1" minOccurs="0" maxOccurs="1"/>
            <xs:element ref="Element2" minOccurs="0" maxOccurs="1"/>
            <xs:element ref="Element3" minOccurs="0" maxOccurs="unbounded"/>
        </xs:sequence>
        <xs:attribute name="stateName" type="xs:string" use="required"/>
        <xs:attribute name="A" type="xs:string" use="required"/>
        <xs:attribute name="B" type="xs:string" use="required"/>
        <xs:attribute name="C" type="xs:string" use="optional"/>
    </xs:complexType>
</xs:element>
<xs:element name="Sequence">
    <xs:complexType>
        <xs:sequence>
            <xs:element ref="Transition" minOccurs="0" maxOccurs="unbounded"/>
        </xs:sequence>
        <xs:attribute name="name" type="xs:string" use="optional"/>
        <xs:attribute ref="xml:base"/>
    </xs:complexType>
    <xs:unique name="uniqueTransition">
        <xs:selector xpath=".//Transition"/>
        <xs:field xpath="@stateName"/>
        <xs:field xpath="@A"/>
        <xs:field xpath="@B"/>
        <xs:field xpath="@C"/>
    </xs:unique>
</xs:element>

和StateRelations部分定义如下。 “ stateName1 ”实际上是与Transition的“ stateName ”(键)相关的外键(keyref)。 注意:Relation元素实际上是递归的。

<xs:element name="Relation">
    <xs:complexType>
        <xs:sequence>
            <xs:element ref="Relation" minOccurs="0" maxOccurs="unbounded"/>
        </xs:sequence>
        <xs:attribute name="stateName1" type="xs:string" use="required"/>
    </xs:complexType>
</xs:element>
<xs:element name="StateRelations">
    <xs:complexType>
        <xs:sequence>
            <xs:element ref="Relation" minOccurs="0" maxOccurs="unbounded"/>
        </xs:sequence>
        <xs:attribute name="name" type="xs:string" use="optional"/>
        <xs:attribute ref="xml:base"/>
    </xs:complexType>
</xs:element>

问题出现在以下场景中。由于Transition具有基于4个属性的唯一约束,因此以下XML有效。

<Transition stateName="S3" A="a1" B="b1" C="c"/>
<Transition stateName="S3" A="a" B="b" C="c"/>

正如您所看到的, stateName = S3 可以重复多次。但这种重复打破了过渡与关系之间的主要外键关系。原因:stateName可以在Transitions中重复。现在,我们在这里发生冲突。我的最终目标是

  1. 基于4个属性的唯一序列

  2. 并且StateRelations中的每个 stateName1 都应该是有效的 stateName 在Transitions中定义。

  3. 直到现在,我知道key-keyref在我的场景中不起作用所以我开始研究断言,但我无法让它工作。我尝试了以下但似乎没有任何工作。

        <xs:element name="Relation">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="Relation" minOccurs="0" maxOccurs="unbounded"/>
            </xs:sequence>
            <xs:attribute name="stateName1" type="xs:string" use="required"/>
    
            <xs:assert test="matches( .//Transition/@stateName , @stateName1 )"/>
            <xs:assert test="/Replay/Sequence/Transition[contains(@stateName, @stateName1)]" />
            <xs:assert test="/Replay/Sequence/Transition[contains(@stateName, string( @stateName1 ))]/@stateName = string(@stateName1) "/>
    
        </xs:complexType>
    </xs:element>
    

    编辑:这是XSD(我省略了一些细节)。 现在,我想以某种方式验证/Replay/StateRelations/Relation/@stateName1中是否存在/Replay/Sequence/Transition/@stateName。我无法使用key / keyref,因为/Replay/Sequence/Transition/@stateName不会是唯一的。

    <Replay>
       <xs:element name="Relation">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="Relation" minOccurs="0" maxOccurs="unbounded"/>
            </xs:sequence>
            <xs:attribute name="stateName1" type="xs:string" use="required"/>
            <xs:assert test="matches( .//Transition/@stateName , @stateName1 )"/>
            <xs:assert test="/Replay/Sequence/Transition[contains(@stateName, @stateName1)]" />
            <xs:assert test="/Replay/Sequence/Transition[contains(@stateName, string( @stateName1 ))]/@stateName = string(@stateName1) "/>
        </xs:complexType>
    </xs:element>
    <xs:element name="StateRelations">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="Relation" minOccurs="0" maxOccurs="unbounded"/>
            </xs:sequence>
            <xs:attribute name="name" type="xs:string" use="optional"/>
            <xs:attribute ref="xml:base"/>
        </xs:complexType>
    </xs:element>
    
    <xs:element name="Transition">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="Element1" minOccurs="0" maxOccurs="1"/>
                <xs:element ref="Element2" minOccurs="0" maxOccurs="1"/>
                <xs:element ref="Element3" minOccurs="0" maxOccurs="unbounded"/>
            </xs:sequence>
            <xs:attribute name="stateName" type="xs:string" use="required"/>
            <xs:attribute name="A" type="xs:string" use="required"/>
            <xs:attribute name="B" type="xs:string" use="required"/>
            <xs:attribute name="C" type="xs:string" use="optional"/>
        </xs:complexType>
    </xs:element>
    <xs:element name="Sequence">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="Transition" minOccurs="0" maxOccurs="unbounded"/>
            </xs:sequence>
            <xs:attribute name="name" type="xs:string" use="optional"/>
            <xs:attribute ref="xml:base"/>
        </xs:complexType>
        <xs:unique name="uniqueTransition">
            <xs:selector xpath=".//Transition"/>
            <xs:field xpath="@stateName"/>
            <xs:field xpath="@A"/>
            <xs:field xpath="@B"/>
            <xs:field xpath="@C"/>
        </xs:unique>
    </xs:element>
    </Replay>
    

1 个答案:

答案 0 :(得分:0)

我在处理文档的顶级结构时遇到了问题。从你的非工作断言中的路径猜测,我猜你的顶级元素是Replay,它有一个分支/Replay/Sequence/Transition和另一个单独的分支/Replay/StateRelations/Relation

如果是这种情况,那么定义TransitionRelation之间关系的约束需要在共同祖先的级别定义,即Replay。您可以使用此级别的key / keyref或使用断言来定义它,但是任何一种影响两个不同元素的方法总是需要在共同祖先的级别定义:因为它是以这个祖先为根的树,这是最小的自我 - 包含无效文档的部分。

更具体地说,请注意,断言不能查看以定义断言的元素为根的子树之外的数据。这是关于该元素及其内容的断言,而不是关于该元素的周围环境的断言。