XSD 1.1 检查一个属性是否存在于另一个元素中
XSD 1.1 Check if an attribute exists in another element
我的 XML 文件 Sequence 和 StateRelations 中有 2 个主要部分。序列部分定义为。根据下面定义的 4 个属性,Transition 元素应该是唯一的。
<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”实际上是一个外键(keyref),与Transition的“stateName”(key)相关。 注意:关系元素实际上是递归的。
<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 可以重复多次。但是这种重复破坏了 Transition 和 Relations 之间的主外键关系。原因:stateName 可以在 Transitions 中重复。现在,我们在这里发生了冲突。我的最终目标是
基于 4 个属性的唯一序列
并且 StateRelations 中的每个 stateName1 应该是有效的 stateName
在 Transitions 中定义。
到目前为止,我知道 key-keyref 在我的场景中不起作用,所以我开始研究 assert 但我无法让它工作。我尝试了以下方法,但似乎没有任何效果。
<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>
我无法确定您文档的顶级结构。从您的非工作断言中的路径猜测,我猜您的顶级元素是 Replay,并且它有一个分支 /Replay/Sequence/Transition
,也许还有另一个单独的分支 /Replay/StateRelations/Relation
?
如果是这样,那么定义 Transition
和 Relation
之间关系的约束需要在共同祖先级别定义,即 Replay
。您可以在此级别使用 key/keyref 或使用断言来定义它,但是无论哪种方式,影响两个不同元素的约束始终需要在共同祖先级别定义:因为它是根植于该祖先的树文档中最小的无效自包含部分。
更具体地说,请注意,断言无法查看以定义断言的元素为根的子树之外的数据。它是关于该元素及其内容的断言,而不是关于该元素周围上下文的断言。
我的 XML 文件 Sequence 和 StateRelations 中有 2 个主要部分。序列部分定义为。根据下面定义的 4 个属性,Transition 元素应该是唯一的。
<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”实际上是一个外键(keyref),与Transition的“stateName”(key)相关。 注意:关系元素实际上是递归的。
<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 可以重复多次。但是这种重复破坏了 Transition 和 Relations 之间的主外键关系。原因:stateName 可以在 Transitions 中重复。现在,我们在这里发生了冲突。我的最终目标是
基于 4 个属性的唯一序列
并且 StateRelations 中的每个 stateName1 应该是有效的 stateName 在 Transitions 中定义。
到目前为止,我知道 key-keyref 在我的场景中不起作用,所以我开始研究 assert 但我无法让它工作。我尝试了以下方法,但似乎没有任何效果。
<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>
我无法确定您文档的顶级结构。从您的非工作断言中的路径猜测,我猜您的顶级元素是 Replay,并且它有一个分支 /Replay/Sequence/Transition
,也许还有另一个单独的分支 /Replay/StateRelations/Relation
?
如果是这样,那么定义 Transition
和 Relation
之间关系的约束需要在共同祖先级别定义,即 Replay
。您可以在此级别使用 key/keyref 或使用断言来定义它,但是无论哪种方式,影响两个不同元素的约束始终需要在共同祖先级别定义:因为它是根植于该祖先的树文档中最小的无效自包含部分。
更具体地说,请注意,断言无法查看以定义断言的元素为根的子树之外的数据。它是关于该元素及其内容的断言,而不是关于该元素周围上下文的断言。