我在多个元素上定义了一个唯一约束:define unique constraint based on multiple elements
现在唯一约束看起来像这样:
<xs:unique name="specieSizeGroupLengthAssortment">
<xs:selector xpath="DataRow"/>
<xs:field xpath="Specie"/>
<xs:field xpath="Group"/>
<xs:field xpath="Length"/>
<xs:field xpath="Type"/>
</xs:unique>
现在假设元素“Type”是可选的。到目前为止,我的搜索和我的测试证实,这个唯一约束仅适用于具有唯一约束中定义的所有子元素的元素。 例如:
由于唯一约束,这应该是无效:
<DataRow>
<Specie>A</Specie>
<Length>100</Length>
<Group>A</Group>
</DataRow>
<DataRow>
<Specie>A</Spacie>
<Length>100</Length>
<Group>A</Group>
</DataRow>
这应该有效:
<DataRow>
<Specie>A</Specie>
<Length>100</Length>
<Group>A</Group>
</DataRow>
<DataRow>
<Specie>A</Spacie>
<Length>100</Length>
<Group>A</Group>
<Type>D</Type>
</DataRow>
这应该是无效:
<DataRow>
<Specie>A</Specie>
<Length>100</Length>
<Group>A</Group>
<Type>D</Type>
</DataRow>
<DataRow>
<Specie>A</Spacie>
<Length>100</Length>
<Group>A</Group>
<Type>D</Type>
</DataRow>
是否可以创建一个可以进行此类验证的XSD架构?
答案 0 :(得分:3)
规范声明field
约束中的每个unique
必须标识单个节点(元素或属性),其内容或值必须是简单类型,才能在约束中使用。
XML Schema part 1: Structures, §3.11.1,我的大胆。
因此,您似乎无法在唯一性约束中使用可选元素。这由用于验证这些约束的逐步规则(§3.11.4)支持:
3对于目标节点集中的每个节点,所有{fields}(以该节点作为上下文节点)将评估为空节点集或具有恰好一个成员的节点集,其必须具有一个简单的类型。 [定义:]调用元素的[模式规范化值]中定义的类型确定值的序列(如[XML Schemas:Datatypes]中所定义)和/或那些节点集中的属性信息项,以便节点的键序列 4 [定义:]调用·目标节点集的子集·所有{fields}求值为具有一个成员的节点集,该成员是具有限定节点集的简单类型的元素或属性节点即可。以下适当的情况必须如此:
4.1如果{identity-constraint category}是唯一的,那么合格节点集的两个成员没有·key-sequences·其成员成对相等,如[XML Schemas:Datatypes]中的Equal所定义。
[...]
这明确地将唯一性检查定义为仅应用于“限定节点集”,即与selector
匹配的节点 all 其field
s < / p>
答案 1 :(得分:1)
我想我的方法错了。唯一约束允许缺少字段;关键限制没有。
该语言非常模糊,但在XSD 1.1版本中更易于理解,因为已添加了一些注释。我不认为两个版本之间的功能有任何(故意)改变。
{selector}以元素信息项作为上下文节点,求值为一个节点集(如[XPath]中所定义)。 [定义:]将此称为目标节点集。
将所有{fields}求值的目标节点集的子集调用为具有一个成员的节点集,该成员是具有限定节点集的简单类型的元素或属性节点。 / p>
因此,如果某个选定节点的某个字段缺少值,则此节点不属于限定节点集。
这意味着对于“唯一”,将忽略不存在字段的所选节点。
这意味着对于“key”,如果缺少其中一个字段,则数据无效。
我还得出结论,发布的原始模式几乎完成了所需的操作,但第一个示例不是无效的:对于两个选定的节点都有一个字段缺失,因此在选定的节点中都没有包含选定的节点 - 因此,唯一约束无效。要使其无效,您将需要第二个“唯一”约束,该约束仅列出前三个字段。但是,如果这三个字段相同,即使第四个字段存在,您也会得到有效性错误。
在XSD 1.1中,您可以使用断言
来解决问题test="count(DataRow) = count(distinct-values(DataRow/concat(
Specie, '|', Length, '|', Group, '|', Type)))