如何使用key / keyrefs为相同类型的嵌套元素创建xml架构

时间:2010-05-19 21:10:01

标签: xml xsd schema xsd-validation keyref

我定期使用一些XML文件,希望DTD可以提供更好的验证。所以我开始阅读有关模式的内容,看看是否会帮助我。到目前为止,我已经能够创造出几乎像我需要的东西,除了一件。我希望能够将元素的属性限制为具有相同元素类型的兄弟或祖先元素的不同属性的值。使用XML Schema key / 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 可以“扩展”,这没有意义,但我没关系。

同样重要的是,两个家庭节点都应该能够拥有名为 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 不是分配给“extends”的有效密钥,因为它不是 nodeContainer 中第一级节点的一部分。但是,无论如何都要写密钥/ keyrefs来使它们成为有效密钥吗?键/ keyref定义的位置是否有所不同?我的xpaths是否过于具体(它们如何不那么具体)?

1 个答案:

答案 0 :(得分:0)

如果将UniqueNodes的XPath选择器更改为

,会发生什么
<xs:selector xpath="nodeContainer//node"/>

换句话说 - nodeContainer下的任何节点元素。 这不会允许你想要实现的目标吗?