我定期处理一些 XML 文件,并希望获得比 DTD 提供的更好的验证。所以我开始阅读模式,看看是否能帮助我。到目前为止,我已经能够创造出几乎像我需要的东西,除了一件。我希望能够将元素的属性限制为具有相同元素类型的兄弟元素或祖先元素的不同属性的值。这甚至可以使用 XML Schema 键/keyref 限制吗?
我有一个看起来像这样的文件:
<nodeContainer>
<node name="Table">
</node>
<node name="MyHouse">
<node name="RoomWithDoor">
</node>
<node name="DiningRoom" extends="RoomWithDoor">
<node name="DiningTable" extends="Table">
</node>
</node>
</node>
<node name="MySummerHouse">
<node name="DiningRoom">
<node name="DiningTable" extends="Table">
</node>
</node>
</node>
</nodeContainer>
在本文档中,节点可以“扩展”其他节点:
- 兄弟姐妹
- 父母的兄弟姐妹
但是,节点不应“扩展”:
- 父母
- 父母兄弟姐妹的子节点
这意味着MyHouse可以“扩展” Table,这没有意义,但我可以接受。
同样重要的是,两个房屋节点都应该能够拥有自己的名为DiningRoom的节点。
我当前的架构类似于:
<xs:complexType name="node">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="node"/> <!-- node can have other nodes inside it -->
<xs:element ref="leaf"/>
</xs:choice>
<xs:attribute name="name" type="xs:anySimpleType" use="required"/>
<xs:attribute name="extends" type="xs:anySimpleType"/>
</xs:complexType>
<!-- document root -->
<xs:element name="root">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="nodeContainer">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="node"/>
</xs:choice>
</xs:complexType>
</xs:element>
<xs:element ref="otherType"/>
</xs:choice>
</xs:complexType>
<!-- create constrictions -->
<xs:unique name="UniqueNodes">
<xs:selector xpath="nodeContainer/node"/>
<xs:field xpath="@name"/>
</xs:unique>
<xs:keyref refer="UniqueNodes" name="ValidNodeExtends">
<xs:selector xpath=".//node"></xs:selector>
<xs:field xpath="@extends"></xs:field>
</xs:keyref>
</xs:element>
这个模式做了我正在寻找的一部分。它将键设置为nodeContainer中第一级节点的名称,这些键可用于“扩展” nodeContainer或以下任何级别的任何节点。只要我不想在较低级别“扩展”兄弟姐妹,这就是有效的。由于这一行,上面的示例文档无法验证:
<node name="DiningRoom" extends="RoomWithDoor">
在我创建的架构中,RoomWithDoor不是分配给“扩展”的有效键,因为它不是nodeContainer中第一级节点的一部分。但是无论如何要编写密钥/密钥引用以使它们成为有效密钥?键/keyref 定义的放置是否有所不同?我的 xpath 是否过于具体(它们怎么可能不那么具体)?